From e8d15724a4301f8b65334764750586fe99034d1c Mon Sep 17 00:00:00 2001 From: blu3beri Date: Thu, 9 Mar 2023 10:54:33 +0100 Subject: [PATCH] fix: add support for legacy schema and cred def id Signed-off-by: blu3beri --- src/data_types/cred_request.rs | 18 ++++--- src/data_types/issuer_id.rs | 85 +++++++++++++++++----------------- src/data_types/macros.rs | 37 ++++++++++++--- src/services/prover.rs | 26 +++++++---- src/services/verifier.rs | 4 +- src/utils/validation.rs | 59 ++++++++++++++++++++++- tests/utils/mock.rs | 11 +++++ 7 files changed, 174 insertions(+), 66 deletions(-) diff --git a/src/data_types/cred_request.rs b/src/data_types/cred_request.rs index de26c77e..5a68d793 100644 --- a/src/data_types/cred_request.rs +++ b/src/data_types/cred_request.rs @@ -1,6 +1,6 @@ use crate::error::{Result, ValidationError}; use crate::invalid; -use crate::utils::validation::{Validatable, LEGACY_IDENTIFIER}; +use crate::utils::validation::{Validatable, LEGACY_DID_IDENTIFIER}; use super::{cred_def::CredentialDefinitionId, nonce::Nonce}; @@ -29,9 +29,9 @@ impl Validatable for CredentialRequest { } } None => { - if self.cred_def_id.is_legacy() { + if self.cred_def_id.is_legacy_cred_def_identifier() { if let Some(prover_did) = self.prover_did.clone() { - if LEGACY_IDENTIFIER.captures(&prover_did).is_some() { + if LEGACY_DID_IDENTIFIER.captures(&prover_did).is_some() { Ok(()) } else { Err(invalid!("Prover did was supplied, not valid")) @@ -106,10 +106,12 @@ mod cred_req_tests { use super::*; const NEW_IDENTIFIER: &str = "mock:uri"; - const LEGACY_IDENTIFIER: &str = "NcYxiDXkpYi6ov5FcYDi1e"; + const LEGACY_DID_IDENTIFIER: &str = "DXoTtQJNtXtiwWaZAK3rB1"; + const LEGACY_SCHEMA_IDENTIFIER: &str = "DXoTtQJNtXtiwWaZAK3rB1:2:example:1.0"; + const LEGACY_CRED_DEF_IDENTIFIER: &str = "DXoTtQJNtXtiwWaZAK3rB1:3:CL:98153:default"; const ENTROPY: Option<&str> = Some("entropy"); - const PROVER_DID: Option<&str> = Some(LEGACY_IDENTIFIER); + const PROVER_DID: Option<&str> = Some(LEGACY_DID_IDENTIFIER); const MASTER_SERCET_ID: &str = "master:secret:id"; fn cred_def() -> Result<(CredentialDefinition, CredentialKeyCorrectnessProof)> { @@ -140,7 +142,11 @@ mod cred_req_tests { is_legacy: bool, ) -> Result { if is_legacy { - create_credential_offer(LEGACY_IDENTIFIER, LEGACY_IDENTIFIER, &correctness_proof) + create_credential_offer( + LEGACY_SCHEMA_IDENTIFIER, + LEGACY_CRED_DEF_IDENTIFIER, + &correctness_proof, + ) } else { create_credential_offer(NEW_IDENTIFIER, NEW_IDENTIFIER, &correctness_proof) } diff --git a/src/data_types/issuer_id.rs b/src/data_types/issuer_id.rs index 15a1b84e..fe6090cc 100644 --- a/src/data_types/issuer_id.rs +++ b/src/data_types/issuer_id.rs @@ -2,46 +2,47 @@ use crate::impl_anoncreds_object_identifier; impl_anoncreds_object_identifier!(IssuerId); -#[test] -fn should_validate_new_and_legacy_identifiers() { - let valid_uri_identifier_1 = "did:uri:new"; - let valid_uri_identifier_2 = "did:indy:idunion:test:2MZYuPv2Km7Q1eD4GCsSb6"; - let valid_uri_identifier_3 = "did:indy:sovrin:staging:6cgbu8ZPoWTnR5Rv5JcSMB"; - let valid_uri_identifier_4 = "did:indy:sovrin:7Tqg6BwSSWapxgUDm9KKgg"; - let valid_uri_identifier_5 = "did:web:example.com#controller"; - let valid_uri_identifier_6 = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"; - - let invalid_uri_identifier = "::::"; - - let valid_legacy_identifier_1 = "NcYxiDXkpYi6ov5FcYDi1e"; - let valid_legacy_identifier_2 = "VsKV7grR1BUE29mG2Fm2kX"; - - let too_short_legacy_identifier = "abc"; - let too_long_legacy_identifier = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let illegal_base58_legacy_identifier_zero = "0000000000000000000000"; - let illegal_base58_legacy_identifier_captial_o = "OOOOOOOOOOOOOOOOOOOOOO"; - let illegal_base58_legacy_identifier_captial_i = "IIIIIIIIIIIIIIIIIIIIII"; - let illegal_base58_legacy_identifier_lower_l = "llllllllllllllllllllll"; - - // Instantiating a new IssuerId validates it - assert!(IssuerId::new(valid_uri_identifier_1).is_ok()); - assert!(IssuerId::new(valid_uri_identifier_2).is_ok()); - assert!(IssuerId::new(valid_uri_identifier_3).is_ok()); - assert!(IssuerId::new(valid_uri_identifier_4).is_ok()); - assert!(IssuerId::new(valid_uri_identifier_5).is_ok()); - assert!(IssuerId::new(valid_uri_identifier_6).is_ok()); - - assert!(IssuerId::new(invalid_uri_identifier).is_err()); - - assert!(IssuerId::new(valid_legacy_identifier_1).is_ok()); - assert!(IssuerId::new(valid_legacy_identifier_2).is_ok()); - - assert!(IssuerId::new(too_short_legacy_identifier).is_err()); - assert!(IssuerId::new(too_long_legacy_identifier).is_err()); - assert!(IssuerId::new(illegal_base58_legacy_identifier_zero).is_err()); - assert!(IssuerId::new(illegal_base58_legacy_identifier_captial_o).is_err()); - assert!(IssuerId::new(illegal_base58_legacy_identifier_captial_i).is_err()); - assert!(IssuerId::new(illegal_base58_legacy_identifier_lower_l).is_err()); - - assert!(true); +#[cfg(test)] +mod test_issuer_identifiers { + use super::*; + + #[test] + fn should_validate_new_and_legacy_identifiers() { + let valid_uri_identifier_1 = "did:uri:new"; + let valid_uri_identifier_2 = "did:indy:idunion:test:2MZYuPv2Km7Q1eD4GCsSb6"; + let valid_uri_identifier_3 = "did:indy:sovrin:staging:6cgbu8ZPoWTnR5Rv5JcSMB"; + let valid_uri_identifier_4 = "did:indy:sovrin:7Tqg6BwSSWapxgUDm9KKgg"; + let valid_uri_identifier_5 = "did:web:example.com#controller"; + let valid_uri_identifier_6 = "did:key:z6MkhaXgBZDvotDkL5257faiztiGiC2QtKLGpbnnEGta2doK"; + + let invalid_uri_identifier = "::::"; + + let valid_legacy_identifier_1 = "NcYxiDXkpYi6ov5FcYDi1e"; + let valid_legacy_identifier_2 = "VsKV7grR1BUE29mG2Fm2kX"; + + let too_short_legacy_identifier = "abc"; + let illegal_base58_legacy_identifier_zero = "0000000000000000000000"; + let illegal_base58_legacy_identifier_captial_o = "OOOOOOOOOOOOOOOOOOOOOO"; + let illegal_base58_legacy_identifier_captial_i = "IIIIIIIIIIIIIIIIIIIIII"; + let illegal_base58_legacy_identifier_lower_l = "llllllllllllllllllllll"; + + // Instantiating a new IssuerId validates it + assert!(IssuerId::new(valid_uri_identifier_1).is_ok()); + assert!(IssuerId::new(valid_uri_identifier_2).is_ok()); + assert!(IssuerId::new(valid_uri_identifier_3).is_ok()); + assert!(IssuerId::new(valid_uri_identifier_4).is_ok()); + assert!(IssuerId::new(valid_uri_identifier_5).is_ok()); + assert!(IssuerId::new(valid_uri_identifier_6).is_ok()); + + assert!(IssuerId::new(invalid_uri_identifier).is_err()); + + assert!(IssuerId::new(valid_legacy_identifier_1).is_ok()); + assert!(IssuerId::new(valid_legacy_identifier_2).is_ok()); + + assert!(IssuerId::new(too_short_legacy_identifier).is_err()); + assert!(IssuerId::new(illegal_base58_legacy_identifier_zero).is_err()); + assert!(IssuerId::new(illegal_base58_legacy_identifier_captial_o).is_err()); + assert!(IssuerId::new(illegal_base58_legacy_identifier_captial_i).is_err()); + assert!(IssuerId::new(illegal_base58_legacy_identifier_lower_l).is_err()); + } } diff --git a/src/data_types/macros.rs b/src/data_types/macros.rs index c2d0baa8..726eba73 100644 --- a/src/data_types/macros.rs +++ b/src/data_types/macros.rs @@ -2,7 +2,10 @@ macro_rules! impl_anoncreds_object_identifier { ($i:ident) => { use $crate::error::ValidationError; - use $crate::utils::validation::{Validatable, LEGACY_IDENTIFIER, URI_IDENTIFIER}; + use $crate::utils::validation::{ + Validatable, LEGACY_CRED_DEF_IDENTIFIER, LEGACY_DID_IDENTIFIER, + LEGACY_SCHEMA_IDENTIFIER, URI_IDENTIFIER, + }; #[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize, Serialize, Default)] pub struct $i(pub String); @@ -18,8 +21,16 @@ macro_rules! impl_anoncreds_object_identifier { Ok(s) } - pub fn is_legacy(&self) -> bool { - LEGACY_IDENTIFIER.captures(&self.0).is_some() + pub fn is_legacy_did_identifier(&self) -> bool { + LEGACY_DID_IDENTIFIER.captures(&self.0).is_some() + } + + pub fn is_legacy_cred_def_identifier(&self) -> bool { + LEGACY_CRED_DEF_IDENTIFIER.captures(&self.0).is_some() + } + + pub fn is_legacy_schema_identifier(&self) -> bool { + LEGACY_SCHEMA_IDENTIFIER.captures(&self.0).is_some() } pub fn is_uri(&self) -> bool { @@ -29,6 +40,21 @@ macro_rules! impl_anoncreds_object_identifier { impl Validatable for $i { fn validate(&self) -> Result<(), ValidationError> { + let legacy_regex = match stringify!($i) { + "IssuerId" => &LEGACY_DID_IDENTIFIER, + "CredentialDefinitionId" => &LEGACY_CRED_DEF_IDENTIFIER, + "SchemaId" => &LEGACY_SCHEMA_IDENTIFIER, + // TODO: we do not have correct validation for a revocation registry and definition id + "RevocationRegistryId" => &LEGACY_DID_IDENTIFIER, + "RevocationRegistryDefinitionId" => &LEGACY_DID_IDENTIFIER, + invalid_name => { + return Err($crate::invalid!( + "type: {} does not have a validation regex", + invalid_name, + )) + } + }; + if $crate::utils::validation::URI_IDENTIFIER .captures(&self.0) .is_some() @@ -36,10 +62,7 @@ macro_rules! impl_anoncreds_object_identifier { return Ok(()); } - if $crate::utils::validation::LEGACY_IDENTIFIER - .captures(&self.0) - .is_some() - { + if legacy_regex.captures(&self.0).is_some() { return Ok(()); } diff --git a/src/services/prover.rs b/src/services/prover.rs index 3ac1a1fb..069c1695 100644 --- a/src/services/prover.rs +++ b/src/services/prover.rs @@ -818,9 +818,9 @@ mod tests { const ISSUER_ID: &str = "mock:uri"; const CRED_DEF_ID: &str = "mock:uri"; - const LEGACY_SCHEMA_ID: &str = "NcYxiDXkpYi6ov5FcYDi1e"; - const LEGACY_ISSUER_ID: &str = "NcYxiDXkpYi6ov5FcYDi1e"; - const LEGACY_CRED_DEF_ID: &str = "NcYxiDXkpYi6ov5FcYDi1e"; + const LEGACY_DID_IDENTIFIER: &str = "DXoTtQJNtXtiwWaZAK3rB1"; + const LEGACY_SCHEMA_IDENTIFIER: &str = "DXoTtQJNtXtiwWaZAK3rB1:2:example:1.0"; + const LEGACY_CRED_DEF_IDENTIFIER: &str = "DXoTtQJNtXtiwWaZAK3rB1:3:CL:98153:default"; fn _master_secret() -> MasterSecret { MasterSecret::new().expect("Error creating prover master secret") @@ -851,15 +851,21 @@ mod tests { } fn _legacy_schema() -> Schema { - create_schema("test", "1.0", LEGACY_ISSUER_ID, ["a", "b", "c"][..].into()).unwrap() + create_schema( + "test", + "1.0", + LEGACY_DID_IDENTIFIER, + ["a", "b", "c"][..].into(), + ) + .unwrap() } fn _legacy_cred_def_and_key_correctness_proof( ) -> (CredentialDefinition, CredentialKeyCorrectnessProof) { let (cred_def, _, key_correctness_proof) = create_credential_definition( - LEGACY_SCHEMA_ID, + LEGACY_SCHEMA_IDENTIFIER, &_legacy_schema(), - LEGACY_ISSUER_ID, + LEGACY_DID_IDENTIFIER, "tag", SignatureType::CL, CredentialDefinitionConfig { @@ -873,8 +879,12 @@ mod tests { fn _legacy_cred_offer( key_correctness_proof: CredentialKeyCorrectnessProof, ) -> CredentialOffer { - create_credential_offer(LEGACY_SCHEMA_ID, LEGACY_CRED_DEF_ID, &key_correctness_proof) - .unwrap() + create_credential_offer( + LEGACY_SCHEMA_IDENTIFIER, + LEGACY_CRED_DEF_IDENTIFIER, + &key_correctness_proof, + ) + .unwrap() } #[test] diff --git a/src/services/verifier.rs b/src/services/verifier.rs index 4c53368b..25555555 100644 --- a/src/services/verifier.rs +++ b/src/services/verifier.rs @@ -22,7 +22,7 @@ use crate::ursa::cl::{ RevocationRegistry as CryptoRevocationRegistry, }; use crate::utils::query::Query; -use crate::utils::validation::LEGACY_IDENTIFIER; +use crate::utils::validation::LEGACY_DID_IDENTIFIER; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct Filter { @@ -804,7 +804,7 @@ fn precess_filed(filed: &str, filter_value: impl Into, tag_value: &str) // means that we only allow legacy identifiers which can be detected with a simple regex. If // they are not in the legacy format, we do not support this. if (filed == "schema_issuer_did" || filed == "issuer_did") - && (LEGACY_IDENTIFIER.captures(&filter_value).is_none()) + && (LEGACY_DID_IDENTIFIER.captures(&filter_value).is_none()) { return Err(err_msg!( ProofRejected, diff --git a/src/utils/validation.rs b/src/utils/validation.rs index 1b84ae0e..d3f4067d 100644 --- a/src/utils/validation.rs +++ b/src/utils/validation.rs @@ -13,9 +13,16 @@ pub static URI_IDENTIFIER: Lazy = /// This is used for legacy indy identifiers that we will keep supporting for /// backwards compatibility. This might validate invalid identifiers if they happen /// to fall within the base58 alphabet, but there is not much we can do about that. -pub static LEGACY_IDENTIFIER: Lazy = +pub static LEGACY_DID_IDENTIFIER: Lazy = Lazy::new(|| Regex::new("^[1-9A-HJ-NP-Za-km-z]{21,22}$").unwrap()); +pub static LEGACY_SCHEMA_IDENTIFIER: Lazy = + Lazy::new(|| Regex::new("^[1-9A-HJ-NP-Za-km-z]{21,22}:2:.+:[0-9.]+$").unwrap()); + +pub static LEGACY_CRED_DEF_IDENTIFIER: Lazy = Lazy::new(|| { + Regex::new("^[1-9A-HJ-NP-Za-km-z]{21,22}:3:CL:(([1-9][0-9]*)|([a-zA-Z0-9]{21,22}:2:.+:[0-9.]+)):(.+)?$").unwrap() +}); + pub fn is_uri_identifier(id: &str) -> bool { URI_IDENTIFIER.captures(id).is_some() } @@ -36,3 +43,53 @@ pub trait Validatable { Ok(()) } } + +#[cfg(test)] +mod test_identifiers { + use super::*; + + #[test] + fn should_validate_valid_identifiers() { + let valid_uri_identifier = "mock:uri"; + let valid_legacy_schema_identifier = "DXoTtQJNtXtiwWaZAK3rB1:2:example:1.0"; + let valid_legacy_cred_def_identifier = "DXoTtQJNtXtiwWaZAK3rB1:3:CL:98153:default"; + let valid_legacy_did_identifier = "DXoTtQJNtXtiwWaZAK3rB1"; + + assert!(URI_IDENTIFIER.captures(valid_uri_identifier).is_some()); + assert!(LEGACY_SCHEMA_IDENTIFIER + .captures(valid_legacy_schema_identifier) + .is_some()); + assert!(LEGACY_CRED_DEF_IDENTIFIER + .captures(valid_legacy_cred_def_identifier) + .is_some()); + assert!(LEGACY_DID_IDENTIFIER + .captures(valid_legacy_did_identifier) + .is_some()); + } + + #[test] + fn should_not_validate_invalid_identifiers() { + let invalid_uri_identifier = "DXoTtQJNtXtiwWaZAK3rB1"; + let invalid_legacy_schema_identifier = "invalid:id"; + let invalid_legacy_cred_def_identifier = "invalid:id"; + let invalid_legacy_did_identifier = "invalid:id"; + + assert!(URI_IDENTIFIER.captures(invalid_uri_identifier).is_none()); + assert!(LEGACY_DID_IDENTIFIER + .captures(invalid_legacy_schema_identifier) + .is_none()); + assert!(LEGACY_CRED_DEF_IDENTIFIER + .captures(invalid_legacy_cred_def_identifier) + .is_none()); + assert!(LEGACY_DID_IDENTIFIER + .captures(invalid_legacy_did_identifier) + .is_none()); + + assert!(LEGACY_SCHEMA_IDENTIFIER + .captures("DXoTtQJNtXtiwWaZAK3rB1:3:example:1.0") + .is_none()); + assert!(LEGACY_CRED_DEF_IDENTIFIER + .captures("DXoTtQJNtXtiwWaZAK3rB1:4:CL:98153:default") + .is_none()); + } +} diff --git a/tests/utils/mock.rs b/tests/utils/mock.rs index 623c0992..619c6e32 100644 --- a/tests/utils/mock.rs +++ b/tests/utils/mock.rs @@ -23,19 +23,23 @@ use anoncreds::{ verifier, }; +#[allow(unused)] pub struct TestError(String); // {cred_def_id: { // schema_id, credential_values, support_revocation, rev_reg_id, rev_idx // }} +#[allow(unused)] pub type IssuerValues<'a> = HashMap<&'a str, (&'a str, HashMap<&'a str, &'a str>, bool, &'a str, u32)>; // {cred_def_id: { // attribute_per_credential, predicate_for_credential }} +#[allow(unused)] pub type ProverValues<'a> = HashMap<&'a str, (Vec<&'a str>, Vec<&'a str>)>; // { rev_reg_def_id: {req_timestamp, override_timestamp} } +#[allow(unused)] pub type Override<'a> = HashMap<&'a RevocationRegistryDefinitionId, HashMap>; #[derive(Debug)] @@ -48,6 +52,7 @@ pub struct Mock<'a> { } impl<'a> Mock<'a> { + #[allow(unused)] pub fn new( issuer_ids: &[&'a str], prover_ids: &[&'a str], @@ -72,6 +77,7 @@ impl<'a> Mock<'a> { } } + #[allow(unused)] pub fn verifer_verifies_presentations_for_requests( &self, presentations: &[Presentation], @@ -110,6 +116,7 @@ impl<'a> Mock<'a> { // issuer wallet holds all data relating to cred def and rev def // prover wallet contains the cred offers from the credentials // ledger holds the rev reg def / rev reg info + #[allow(unused)] pub fn issuer_setup( &mut self, issuer_id: &'static str, @@ -218,6 +225,7 @@ impl<'a> Mock<'a> { } } + #[allow(unused)] fn issuer_create_credential( &self, issuer_wallet: &IssuerWallet, @@ -290,6 +298,7 @@ impl<'a> Mock<'a> { // prover requests and gets credential stored in their wallets // This updates ledger on revocation reg also + #[allow(unused)] pub fn issuer_create_credential_and_store_in_prover_wallet( &mut self, issuer_id: &'static str, @@ -373,6 +382,7 @@ impl<'a> Mock<'a> { } } + #[allow(unused)] pub fn prover_creates_revocation_states( &mut self, prover_id: &'static str, @@ -403,6 +413,7 @@ impl<'a> Mock<'a> { self.prover_wallets.get_mut(prover_id).unwrap().rev_states = rev_states; } + #[allow(unused)] pub fn prover_creates_presentation( &self, prover_id: &'static str,