diff --git a/anoncreds/src/data_types/anoncreds/cred_def.rs b/anoncreds/src/data_types/anoncreds/cred_def.rs index 1a6567c1..a97e8467 100644 --- a/anoncreds/src/data_types/anoncreds/cred_def.rs +++ b/anoncreds/src/data_types/anoncreds/cred_def.rs @@ -3,7 +3,7 @@ use std::str::FromStr; use crate::{data_types::ConversionError, impl_anoncreds_object_identifier}; -use super::schema::SchemaId; +use super::{issuer_id::IssuerId, schema::SchemaId}; pub const CL_SIGNATURE_TYPE: &str = "CL"; @@ -33,12 +33,14 @@ pub struct CredentialDefinitionData { } #[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] pub struct CredentialDefinition { pub schema_id: SchemaId, #[serde(rename = "type")] pub signature_type: SignatureType, pub tag: String, pub value: CredentialDefinitionData, + pub issuer_id: IssuerId, } impl CredentialDefinition { diff --git a/anoncreds/src/data_types/anoncreds/issuer_id.rs b/anoncreds/src/data_types/anoncreds/issuer_id.rs new file mode 100644 index 00000000..15a1b84e --- /dev/null +++ b/anoncreds/src/data_types/anoncreds/issuer_id.rs @@ -0,0 +1,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); +} diff --git a/anoncreds/src/data_types/anoncreds/macros.rs b/anoncreds/src/data_types/anoncreds/macros.rs index 8077ef7e..55fd2cc3 100644 --- a/anoncreds/src/data_types/anoncreds/macros.rs +++ b/anoncreds/src/data_types/anoncreds/macros.rs @@ -11,27 +11,32 @@ macro_rules! impl_anoncreds_object_identifier { pub fn new(s: impl Into) -> Result { let s = Self(s.into()); - s.validate()?; + $crate::data_types::Validatable::validate(&s)?; Ok(s) } } impl $crate::data_types::Validatable for $i { fn validate(&self) -> Result<(), $crate::data_types::ValidationError> { - // TODO: stricten the URI regex. - // Right now everything after the first colon is allowed, we might want to restrict - // this - let uri_regex = regex::Regex::new(r"^[a-zA-Z0-9\+\-\.]+:.+$").unwrap(); - uri_regex + if $crate::utils::validation::URI_IDENTIFIER .captures(&self.0) - .ok_or_else(|| { - indy_utils::invalid!( - "type: {}, identifier: {} is invalid. It MUST be a URI.", - stringify!($i), - self.0 - ) - }) - .map(|_| ()) + .is_some() + { + return Ok(()); + } + + if $crate::utils::validation::LEGACY_IDENTIFIER + .captures(&self.0) + .is_some() + { + return Ok(()); + } + + Err(indy_utils::invalid!( + "type: {}, identifier: {} is invalid. It MUST be a URI or legacy identifier.", + stringify!($i), + self.0 + )) } } diff --git a/anoncreds/src/data_types/anoncreds/mod.rs b/anoncreds/src/data_types/anoncreds/mod.rs index a6a8bc3c..2a2ebe3a 100644 --- a/anoncreds/src/data_types/anoncreds/mod.rs +++ b/anoncreds/src/data_types/anoncreds/mod.rs @@ -33,3 +33,6 @@ pub mod schema; /// Macros for the data types pub mod macros; + +/// Identifier wrapper for the issuer +pub mod issuer_id; diff --git a/anoncreds/src/data_types/anoncreds/nonce.rs b/anoncreds/src/data_types/anoncreds/nonce.rs index f5178865..d5da6d25 100644 --- a/anoncreds/src/data_types/anoncreds/nonce.rs +++ b/anoncreds/src/data_types/anoncreds/nonce.rs @@ -213,7 +213,6 @@ mod tests { "1a", ]; for v in invalid.iter() { - println!("try {}", v); assert!(Nonce::try_from(*v).is_err()) } } diff --git a/anoncreds/src/data_types/anoncreds/schema.rs b/anoncreds/src/data_types/anoncreds/schema.rs index 7a38ffe9..97566cd7 100644 --- a/anoncreds/src/data_types/anoncreds/schema.rs +++ b/anoncreds/src/data_types/anoncreds/schema.rs @@ -4,6 +4,8 @@ use crate::impl_anoncreds_object_identifier; use std::collections::HashSet; use std::iter::FromIterator; +use super::issuer_id::IssuerId; + pub const MAX_ATTRIBUTES_COUNT: usize = 125; impl_anoncreds_object_identifier!(SchemaId); @@ -13,8 +15,8 @@ impl_anoncreds_object_identifier!(SchemaId); pub struct Schema { pub name: String, pub version: String, - #[serde(rename = "attrNames")] pub attr_names: AttributeNames, + pub issuer_id: IssuerId, } #[derive(Debug, Clone, Serialize, Deserialize, Default)] @@ -83,6 +85,7 @@ mod test_schema_validation { "name": "gvt", "version": "1.0", "attrNames": ["aaa", "bbb", "ccc"], + "issuerId": "bob" }) .to_string(); @@ -92,7 +95,7 @@ mod test_schema_validation { } #[test] - fn test_invalid_name_schema() { + fn test_invalid_schema() { let schema_json = json!({ "name": "gvt1", "version": "1.0", @@ -100,18 +103,6 @@ mod test_schema_validation { }) .to_string(); - serde_json::from_str::(&schema_json).unwrap(); - } - - #[test] - fn test_invalid_version_schema() { - let schema_json = json!({ - "name": "gvt", - "version": "1.1", - "attrNames": ["aaa", "bbb", "ccc"], - }) - .to_string(); - - serde_json::from_str::(&schema_json).unwrap(); + assert!(serde_json::from_str::(&schema_json).is_err()); } } diff --git a/anoncreds/src/ffi/cred_def.rs b/anoncreds/src/ffi/cred_def.rs index 4c2a17a3..99daaf94 100644 --- a/anoncreds/src/ffi/cred_def.rs +++ b/anoncreds/src/ffi/cred_def.rs @@ -18,6 +18,7 @@ pub extern "C" fn anoncreds_create_credential_definition( schema_id: FfiStr, schema: ObjectHandle, tag: FfiStr, + issuer_id: FfiStr, signature_type: FfiStr, support_revocation: i8, cred_def_p: *mut ObjectHandle, @@ -38,9 +39,13 @@ pub extern "C" fn anoncreds_create_credential_definition( .ok_or_else(|| err_msg!("Missing signature type"))?; SignatureType::from_str(stype).map_err(err_map!(Input))? }; + let issuer_id = issuer_id + .as_opt_str() + .ok_or_else(|| err_msg!("Missing issuer id"))?; let (cred_def, cred_def_pvt, key_proof) = create_credential_definition( schema_id, schema.load()?.cast_ref()?, + issuer_id, tag, signature_type, CredentialDefinitionConfig { diff --git a/anoncreds/src/ffi/schema.rs b/anoncreds/src/ffi/schema.rs index 3221536c..a9c50840 100644 --- a/anoncreds/src/ffi/schema.rs +++ b/anoncreds/src/ffi/schema.rs @@ -10,6 +10,7 @@ use crate::services::issuer::create_schema; pub extern "C" fn anoncreds_create_schema( schema_name: FfiStr, schema_version: FfiStr, + issuer_id: FfiStr, attr_names: FfiStrList, result_p: *mut ObjectHandle, ) -> ErrorCode { @@ -21,9 +22,13 @@ pub extern "C" fn anoncreds_create_schema( let schema_version = schema_version .as_opt_str() .ok_or_else(|| err_msg!("Missing schema version"))?; + let issuer_id = issuer_id + .as_opt_str() + .ok_or_else(|| err_msg!("Missing issuer_id version"))?; let schema = create_schema( schema_name, schema_version, + issuer_id, attr_names.to_string_vec()?.into(), )?; let handle = ObjectHandle::create(schema)?; diff --git a/anoncreds/src/lib.rs b/anoncreds/src/lib.rs index 3bc5f597..e24b1e56 100644 --- a/anoncreds/src/lib.rs +++ b/anoncreds/src/lib.rs @@ -23,6 +23,8 @@ pub use self::error::{Error, ErrorKind}; mod services; pub use services::*; +mod utils; + #[cfg(feature = "ffi")] mod ffi; diff --git a/anoncreds/src/services/issuer.rs b/anoncreds/src/services/issuer.rs index 4063220f..160d2346 100644 --- a/anoncreds/src/services/issuer.rs +++ b/anoncreds/src/services/issuer.rs @@ -5,6 +5,7 @@ use indy_utils::ValidationError; use super::types::*; use crate::data_types::anoncreds::cred_def::CredentialDefinitionId; +use crate::data_types::anoncreds::issuer_id::IssuerId; use crate::data_types::anoncreds::rev_reg::RevocationRegistryId; use crate::data_types::anoncreds::schema::SchemaId; use crate::data_types::anoncreds::{ @@ -26,29 +27,37 @@ use crate::ursa::cl::{ use super::tails::{TailsFileReader, TailsReader, TailsWriter}; -pub fn create_schema( +pub fn create_schema( schema_name: &str, schema_version: &str, + issuer_id: II, attr_names: AttributeNames, -) -> Result { +) -> Result +where + II: TryInto, +{ trace!( - "create_schema >>> schema_name: {:?}, schema_version: {:?}, attr_names: {:?}", + "create_schema >>> schema_name: {}, schema_version: {}, attr_names: {:?}", schema_name, schema_version, - attr_names + attr_names, ); + let issuer_id = issuer_id.try_into()?; + let schema = Schema { name: schema_name.to_string(), version: schema_version.to_string(), + issuer_id, attr_names, }; Ok(schema) } -pub fn create_credential_definition( +pub fn create_credential_definition( schema_id: SI, schema: &Schema, + issuer_id: II, tag: &str, signature_type: SignatureType, config: CredentialDefinitionConfig, @@ -59,12 +68,14 @@ pub fn create_credential_definition( )> where SI: TryInto, + II: TryInto, { trace!( "create_credential_definition >>> schema: {:?}, config: {:?}", schema, config ); + let issuer_id = issuer_id.try_into()?; let schema_id = schema_id.try_into()?; let credential_schema = build_credential_schema(&schema.attr_names.0)?; @@ -80,6 +91,7 @@ where let cred_def = CredentialDefinition { schema_id, signature_type, + issuer_id, tag: tag.to_owned(), value: CredentialDefinitionData { primary: credential_public_key.get_primary_key()?.try_clone()?, diff --git a/anoncreds/src/services/verifier.rs b/anoncreds/src/services/verifier.rs index 86911506..ec973c44 100644 --- a/anoncreds/src/services/verifier.rs +++ b/anoncreds/src/services/verifier.rs @@ -7,6 +7,7 @@ use super::helpers::*; use super::types::*; use crate::data_types::anoncreds::cred_def::CredentialDefinition; use crate::data_types::anoncreds::cred_def::CredentialDefinitionId; +use crate::data_types::anoncreds::issuer_id::IssuerId; use crate::data_types::anoncreds::rev_reg::RevocationRegistryId; use crate::data_types::anoncreds::rev_reg_def::RevocationRegistryDefinitionId; use crate::data_types::anoncreds::schema::Schema; @@ -18,15 +19,16 @@ use crate::data_types::anoncreds::{ }; use crate::error::Result; use crate::ursa::cl::{verifier::Verifier as CryptoVerifier, CredentialPublicKey}; +use crate::utils::validation::LEGACY_IDENTIFIER; use indy_utils::query::Query; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct Filter { schema_id: SchemaId, - schema_issuer_did: String, + schema_issuer_id: IssuerId, schema_name: String, schema_version: String, - issuer_did: String, + issuer_id: IssuerId, cred_def_id: CredentialDefinitionId, } @@ -64,6 +66,8 @@ pub fn verify_presentation( verify_requested_restrictions( pres_req, + schemas, + cred_defs, &presentation.requested_proof, &received_revealed_attrs, &received_unrevealed_attrs, @@ -565,6 +569,8 @@ fn verify_revealed_attribute_value( fn verify_requested_restrictions( pres_req: &PresentationRequestPayload, + schemas: &HashMap<&SchemaId, &Schema>, + cred_defs: &HashMap<&CredentialDefinitionId, &CredentialDefinition>, requested_proof: &RequestedProof, received_revealed_attrs: &HashMap, received_unrevealed_attrs: &HashMap, @@ -584,9 +590,47 @@ fn verify_requested_restrictions( .map(|(referent, info)| (referent.to_string(), info.clone())) .collect(); + let requested_attributes_queries = pres_req + .requested_attributes + .iter() + .filter_map(|(_, info)| info.restrictions.to_owned()); + + let requested_predicates_queries = pres_req + .requested_predicates + .iter() + .filter_map(|(_, info)| info.restrictions.to_owned()); + + let filter_tags: Vec = requested_attributes_queries + .chain(requested_predicates_queries) + .flat_map(|r| { + r.get_name() + .iter() + .map(|n| n.to_owned().to_owned()) + .collect::>() + }) + .collect(); + + // We check whether both the `issuer_id` and `issuer_did` are included. Since `issuer_did` will + // only be used for legacy support and `issuer_id` will be the new restriction tag, we do not + // allow mixing them. + if filter_tags.contains(&"issuer_id".to_owned()) + && filter_tags.contains(&"issuer_did".to_owned()) + { + return Err(err_msg!("Presentation request contains restriction for `issuer_id` (new) and `issuer_did` (legacy)")); + } + + // We check whether both the `schema_issuer_id` and `schema_issuer_did` are included. Since + // `schema_issuer_did` will only be used for legacy support and `schema_issuer_id` will be the + // new restriction tag, we do not allow mixing them. + if filter_tags.contains(&"schema_issuer_id".to_owned()) + && filter_tags.contains(&"schema_issuer_did".to_owned()) + { + return Err(err_msg!("Presentation request contains both restrictions for `schema_issuer_id` (new) and `schema_issuer_did` (legacy)")); + } + for (referent, info) in requested_attrs.iter() { if let Some(ref query) = info.restrictions { - let filter = gather_filter_info(referent, &proof_attr_identifiers)?; + let filter = gather_filter_info(referent, &proof_attr_identifiers, schemas, cred_defs)?; let attr_value_map: HashMap> = if let Some(name) = info.name.as_ref() @@ -630,7 +674,7 @@ fn verify_requested_restrictions( for (referent, info) in pres_req.requested_predicates.iter() { if let Some(ref query) = info.restrictions { - let filter = gather_filter_info(referent, received_predicates)?; + let filter = gather_filter_info(referent, received_predicates, schemas, cred_defs)?; // start with the predicate requested attribute, which is un-revealed let mut attr_value_map = HashMap::new(); @@ -690,7 +734,12 @@ fn is_self_attested( } } -fn gather_filter_info(referent: &str, identifiers: &HashMap) -> Result { +fn gather_filter_info( + referent: &str, + identifiers: &HashMap, + schemas: &HashMap<&SchemaId, &Schema>, + cred_defs: &HashMap<&CredentialDefinitionId, &CredentialDefinition>, +) -> Result { let identifier = identifiers.get(referent).ok_or_else(|| { err_msg!( InvalidState, @@ -699,26 +748,24 @@ fn gather_filter_info(referent: &str, identifiers: &HashMap) ) })?; - // TODO: how can we get these as as we can not extract them from the ID anymore - let schema_name = String::from(""); - let schema_version = String::from(""); - let schema_issuer_did = String::from(""); - let cred_def_issuer_did = Some(String::from("")); + let schema_id = &identifier.schema_id; + let cred_def_id = &identifier.cred_def_id; - let issuer_did = cred_def_issuer_did.ok_or_else(|| { - err_msg!( - "Invalid Credential Definition ID `{}`: wrong number of parts", - identifier.cred_def_id - ) - })?; + let schema = schemas + .get(schema_id) + .ok_or_else(|| err_msg!("schema_id {schema_id} could not be found in the schemas"))?; + + let cred_def = cred_defs + .get(cred_def_id) + .ok_or_else(|| err_msg!("cred_def_id {cred_def_id} could not be found in the cred_defs"))?; Ok(Filter { - schema_id: identifier.schema_id.to_owned(), - schema_name, - schema_issuer_did, - schema_version, - cred_def_id: identifier.cred_def_id.to_owned(), - issuer_did, + schema_id: schema_id.to_owned(), + schema_name: schema.name.to_owned(), + schema_version: schema.version.to_owned(), + schema_issuer_id: schema.issuer_id.to_owned(), + issuer_id: cred_def.issuer_id.to_owned(), + cred_def_id: cred_def_id.to_owned(), }) } @@ -806,11 +853,17 @@ fn process_filter( ); match tag { tag_ @ "schema_id" => precess_filed(tag_, filter.schema_id.to_string(), tag_value), - tag_ @ "schema_issuer_did" => precess_filed(tag_, &filter.schema_issuer_did, tag_value), + tag_ @ "schema_issuer_did" => { + precess_filed(tag_, filter.schema_issuer_id.to_owned(), tag_value) + } + tag_ @ "schema_issuer_id" => { + precess_filed(tag_, filter.schema_issuer_id.to_owned(), tag_value) + } tag_ @ "schema_name" => precess_filed(tag_, &filter.schema_name, tag_value), tag_ @ "schema_version" => precess_filed(tag_, &filter.schema_version, tag_value), tag_ @ "cred_def_id" => precess_filed(tag_, &filter.cred_def_id.to_string(), tag_value), - tag_ @ "issuer_did" => precess_filed(tag_, &filter.issuer_did, tag_value), + tag_ @ "issuer_did" => precess_filed(tag_, filter.issuer_id.to_owned(), tag_value), + tag_ @ "issuer_id" => precess_filed(tag_, filter.issuer_id.to_owned(), tag_value), x if is_attr_internal_tag(x, attr_value_map) => { check_internal_tag_revealed_value(x, tag_value, attr_value_map) } @@ -821,6 +874,18 @@ fn process_filter( fn precess_filed(filed: &str, filter_value: impl Into, tag_value: &str) -> Result<()> { let filter_value = filter_value.into(); + // We explicitly check here with it is one of the two legacy identifier restrictions. This + // 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" { + if LEGACY_IDENTIFIER.captures(&filter_value).is_none() { + return Err(err_msg!( + ProofRejected, + "\"{}\" value is a legacy identifier tag and therefore only legacy identifiers can be used", + filed, + )); + } + } if filter_value == tag_value { Ok(()) } else { @@ -880,10 +945,10 @@ mod tests { pub const SCHEMA_ID: &str = "123"; pub const SCHEMA_NAME: &str = "Schema Name"; - pub const SCHEMA_ISSUER_DID: &str = "234"; + pub const SCHEMA_ISSUER_ID: &str = "1111111111111111111111"; pub const SCHEMA_VERSION: &str = "1.2.3"; pub const CRED_DEF_ID: &str = "345"; - pub const ISSUER_DID: &str = "456"; + pub const ISSUER_ID: &str = "1111111111111111111111"; fn schema_id_tag() -> String { "schema_id".to_string() @@ -925,10 +990,10 @@ mod tests { Filter { schema_id: SchemaId::new_unchecked(SCHEMA_ID), schema_name: SCHEMA_NAME.to_string(), - schema_issuer_did: SCHEMA_ISSUER_DID.to_string(), + schema_issuer_id: IssuerId::new_unchecked(SCHEMA_ISSUER_ID), schema_version: SCHEMA_VERSION.to_string(), cred_def_id: CredentialDefinitionId::new_unchecked(CRED_DEF_ID), - issuer_did: ISSUER_DID.to_string(), + issuer_id: IssuerId::new_unchecked(ISSUER_ID), } } @@ -1108,12 +1173,12 @@ mod tests { Query::Eq(cred_def_id_tag(), CRED_DEF_ID.to_string()), ]), Query::And(vec![ - Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_DID.to_string()), + Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_ID.to_string()), Query::Eq(schema_name_tag(), SCHEMA_NAME.to_string()), ]), Query::And(vec![ Query::Eq(schema_version_tag(), SCHEMA_VERSION.to_string()), - Query::Eq(issuer_did_tag(), ISSUER_DID.to_string()), + Query::Eq(issuer_did_tag(), ISSUER_ID.to_string()), ]), ]); assert!(_process_operator("zip", &op, &filter, None).is_err()); @@ -1128,12 +1193,12 @@ mod tests { Query::Eq(cred_def_id_tag(), CRED_DEF_ID.to_string()), ]), Query::And(vec![ - Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_DID.to_string()), + Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_ID.to_string()), Query::Eq(schema_name_tag(), SCHEMA_NAME.to_string()), ]), Query::And(vec![ Query::Eq(schema_version_tag(), SCHEMA_VERSION.to_string()), - Query::Eq(issuer_did_tag(), ISSUER_DID.to_string()), + Query::Eq(issuer_did_tag(), ISSUER_ID.to_string()), ]), Query::Not(Box::new(Query::Eq( schema_version_tag(), @@ -1152,12 +1217,12 @@ mod tests { Query::Eq(cred_def_id_tag(), CRED_DEF_ID.to_string()), ]), Query::And(vec![ - Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_DID.to_string()), + Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_ID.to_string()), Query::Eq(schema_name_tag(), SCHEMA_NAME.to_string()), ]), Query::And(vec![ Query::Eq(schema_version_tag(), SCHEMA_VERSION.to_string()), - Query::Eq(issuer_did_tag(), ISSUER_DID.to_string()), + Query::Eq(issuer_did_tag(), ISSUER_ID.to_string()), ]), Query::Not(Box::new(Query::Eq( schema_version_tag(), @@ -1177,7 +1242,7 @@ mod tests { op = Query::And(vec![ Query::Eq(attr_tag_value(), value.to_string()), - Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_DID.to_string()), + Query::Eq(schema_issuer_did_tag(), SCHEMA_ISSUER_ID.to_string()), ]); _process_operator("zip", &op, &filter, Some(value)).unwrap(); diff --git a/anoncreds/src/utils/mod.rs b/anoncreds/src/utils/mod.rs new file mode 100644 index 00000000..be9c90dc --- /dev/null +++ b/anoncreds/src/utils/mod.rs @@ -0,0 +1,2 @@ +/// Functions for quick validation +pub mod validation; diff --git a/anoncreds/src/utils/validation.rs b/anoncreds/src/utils/validation.rs new file mode 100644 index 00000000..f352f163 --- /dev/null +++ b/anoncreds/src/utils/validation.rs @@ -0,0 +1,16 @@ +use once_cell::sync::Lazy; +use regex::Regex; + +// TODO: stricten the URI regex. +// Right now everything after the first colon is allowed, +// we might want to restrict this +pub const URI_IDENTIFIER: Lazy = + Lazy::new(|| Regex::new(r"^[a-zA-Z0-9\+\-\.]+:.+$").unwrap()); + +/// base58 alpahet as defined in +/// https://datatracker.ietf.org/doc/html/draft-msporny-base58#section-2 +/// 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 const LEGACY_IDENTIFIER: Lazy = + Lazy::new(|| Regex::new("^[1-9A-HJ-NP-Za-km-z]{21,22}$").unwrap()); diff --git a/anoncreds/tests/anoncreds_demos.rs b/anoncreds/tests/anoncreds_demos.rs index 7c984d19..8bb17501 100644 --- a/anoncreds/tests/anoncreds_demos.rs +++ b/anoncreds/tests/anoncreds_demos.rs @@ -30,6 +30,7 @@ mod utils; pub static SCHEMA_ID: &str = "mock:uri"; pub static CRED_DEF_ID: &str = "mock:uri"; +pub static ISSUER_ID: &str = "mock:issuer_id/path&q=bar"; pub const GVT_SCHEMA_NAME: &str = "gvt"; pub const GVT_SCHEMA_ATTRIBUTES: &[&str; 4] = &["name", "age", "sex", "height"]; pub static REV_REG_ID: &str = "mock:uri:revregid"; @@ -45,14 +46,19 @@ fn anoncreds_works_for_single_issuer_single_prover() { let mut prover_wallet = ProverWallet::default(); // Issuer creates Schema - would be published to the ledger - let gvt_schema = - issuer::create_schema(GVT_SCHEMA_NAME, "1.0", GVT_SCHEMA_ATTRIBUTES[..].into()) - .expect("Error creating gvt schema for issuer"); + let gvt_schema = issuer::create_schema( + GVT_SCHEMA_NAME, + "1.0", + ISSUER_ID, + GVT_SCHEMA_ATTRIBUTES[..].into(), + ) + .expect("Error creating gvt schema for issuer"); // Issuer creates Credential Definition let cred_def_parts = issuer::create_credential_definition( SCHEMA_ID, &gvt_schema, + ISSUER_ID, "tag", SignatureType::CL, CredentialDefinitionConfig { @@ -218,6 +224,7 @@ fn anoncreds_works_for_single_issuer_single_prover() { "175", revealed_attr_groups.values.get("height").unwrap().raw ); + let valid = verifier::verify_presentation( &presentation, &pres_request, @@ -240,14 +247,19 @@ fn anoncreds_with_revocation_works_for_single_issuer_single_prover() { let mut prover_wallet = ProverWallet::default(); // Issuer creates Schema - would be published to the ledger - let gvt_schema = - issuer::create_schema(GVT_SCHEMA_NAME, "1.0", GVT_SCHEMA_ATTRIBUTES[..].into()) - .expect("Error creating gvt schema for issuer"); + let gvt_schema = issuer::create_schema( + GVT_SCHEMA_NAME, + "1.0", + ISSUER_ID, + GVT_SCHEMA_ATTRIBUTES[..].into(), + ) + .expect("Error creating gvt schema for issuer"); // Issuer creates Credential Definition let (cred_def_pub, cred_def_priv, cred_def_correctness) = issuer::create_credential_definition( SCHEMA_ID, &gvt_schema, + ISSUER_ID, "tag", SignatureType::CL, CredentialDefinitionConfig { @@ -381,7 +393,8 @@ fn anoncreds_with_revocation_works_for_single_issuer_single_prover() { "version":"0.1", "requested_attributes":{ "attr1_referent":{ - "name":"name" + "name":"name", + "issuer_id": ISSUER_ID }, "attr2_referent":{ "name":"sex" diff --git a/indy-utils/src/query.rs b/indy-utils/src/query.rs index b0ce2482..ccae552d 100644 --- a/indy-utils/src/query.rs +++ b/indy-utils/src/query.rs @@ -77,6 +77,28 @@ impl AbstractQuery { } } + pub fn get_name(&self) -> Vec<&K> { + match self { + Self::And(subqueries) | Self::Or(subqueries) => { + subqueries.iter().flat_map(|s| s.get_name()).collect() + } + Self::Exist(subquery_names) => subquery_names + .to_owned() + .iter() + .map(|s| s.to_owned()) + .collect(), + Self::Not(boxed_query) => boxed_query.get_name(), + Self::Eq(tag_name, _) + | Self::Neq(tag_name, _) + | Self::Gt(tag_name, _) + | Self::Gte(tag_name, _) + | Self::Lt(tag_name, _) + | Self::Lte(tag_name, _) + | Self::Like(tag_name, _) + | Self::In(tag_name, _) => vec![tag_name], + } + } + /// Perform a transformation on all field names in query clauses pub fn map_names( self,