From 519937f5e0b402d4175d9a8e755eac70b9ec35e0 Mon Sep 17 00:00:00 2001 From: Abdulbois Date: Mon, 11 Dec 2023 14:40:08 +0500 Subject: [PATCH] Extend demos - Enable issuing and verifying nested array SDs - Fix parts related to disclosing arrayed types - Extend demo with new cases Signed-off-by: Abdulbois --- src/holder.rs | 62 +++++--- src/issuer.rs | 15 +- src/lib.rs | 6 +- src/verifier.rs | 2 +- tests/demos.rs | 323 +++++++++++++++++++++++++++++++++------- tests/utils/fixtures.rs | 297 +++++++++--------------------------- 6 files changed, 389 insertions(+), 316 deletions(-) diff --git a/src/holder.rs b/src/holder.rs index 3f50b92..c444a89 100644 --- a/src/holder.rs +++ b/src/holder.rs @@ -93,31 +93,40 @@ impl SDJWTHolder { claims_to_disclose: Map, ) -> Vec { let mut hash_to_disclosure = Vec::new(); - let default_list = Vec::new(); - let sd_map: HashMap<&str, (&Value, &str)> = sd_jwt_claims.get(SD_DIGESTS_KEY).and_then(Value::as_array).unwrap_or(&default_list).iter().map(|digest| { + let sd_map: HashMap<&str, (&Value, &str)> = sd_jwt_claims.get(SD_DIGESTS_KEY).and_then(Value::as_array).unwrap_or(&default_list).iter().filter_map(|digest| { let digest = digest.as_str().unwrap(); - let disclosure = self.sd_jwt_engine.hash_to_decoded_disclosure[digest].as_array().unwrap(); - (disclosure[1].as_str().unwrap(), (&disclosure[2], digest)) + if let Some(Value::Array(disclosure)) = self.sd_jwt_engine.hash_to_decoded_disclosure.get(digest) { + return Some((disclosure[1].as_str().unwrap(), (&disclosure[2], digest))); + } + None }).collect(); //TODO split to 2 maps for (key_to_disclose, value_to_disclose) in claims_to_disclose { match value_to_disclose { - Value::Null | Value::Bool(true) | Value::Number(_) | Value::String(_) => { /* disclose without children */ } - Value::Array(arr_to_disclose) => { - if let Some(arr) = sd_jwt_claims.get(&key_to_disclose).and_then(Value::as_array) { - hash_to_disclosure.append(&mut self.select_disclosures_from_disclosed_list(&arr, &arr_to_disclose)) + Value::Bool(true) | Value::Number(_) | Value::String(_) => { /* disclose without children */ } + Value::Array(claims_to_disclose) => { + if let Some(sd_jwt_claims) = sd_jwt_claims + .get(&key_to_disclose) + .and_then(Value::as_array) + { + hash_to_disclosure.append(&mut self.select_disclosures_from_disclosed_list(&sd_jwt_claims, &claims_to_disclose)) + } else if let Some(sd_jwt_claims) = sd_map + .get(key_to_disclose.as_str()) + .and_then(|(sd, _)| sd.as_array()) + { + hash_to_disclosure.append(&mut self.select_disclosures_from_disclosed_list(&sd_jwt_claims, &claims_to_disclose)) } } - Value::Object(next_disclosure) if (!next_disclosure.is_empty()) => { - let next_sd_jwt_claims = if let Some(next) = sd_jwt_claims.get(&key_to_disclose).and_then(Value::as_object) { + Value::Object(claims_to_disclose) if (!claims_to_disclose.is_empty()) => { + let sd_jwt_claims = if let Some(next) = sd_jwt_claims.get(&key_to_disclose).and_then(Value::as_object) { next } else { sd_map[key_to_disclose.as_str()].0.as_object().unwrap() }; - hash_to_disclosure.append(&mut self.select_disclosures(next_sd_jwt_claims, next_disclosure)); + hash_to_disclosure.append(&mut self.select_disclosures(sd_jwt_claims, claims_to_disclose)); } Value::Object(_) => { /* disclose without children */ } - Value::Bool(false) => { + Value::Bool(false) | Value::Null => { // skip unrevealed continue } @@ -134,15 +143,32 @@ impl SDJWTHolder { fn select_disclosures_from_disclosed_list(&self, sd_jwt_claims: &Vec, claims_to_disclose: &Vec) -> Vec { let mut hash_to_disclosure: Vec = Vec::new(); - for (claim_to_disclose, claim) in claims_to_disclose.iter().zip(sd_jwt_claims) { - match (claim_to_disclose, claim) { - (Value::Bool(true), Value::Object(claim)) => { - if let Some(Value::String(digest)) = claim.get(SD_LIST_PREFIX) { + for (claim_to_disclose, sd_jwt_claims) in claims_to_disclose.iter().zip(sd_jwt_claims) { + match (claim_to_disclose, sd_jwt_claims) { + (Value::Bool(true), Value::Object(sd_jwt_claims)) => { + if let Some(Value::String(digest)) = sd_jwt_claims.get(SD_LIST_PREFIX) { hash_to_disclosure.push(self.sd_jwt_engine.hash_to_disclosure[digest].to_owned()); } } - (Value::Array(new_claims_to_disclose), Value::Array(claim)) => { - self.select_disclosures_from_disclosed_list(claim, new_claims_to_disclose); + (claim_to_disclose, Value::Object(sd_jwt_claims)) => { + if let Some(Value::String(digest)) = sd_jwt_claims.get(SD_LIST_PREFIX) { + let disclosure = self.sd_jwt_engine.hash_to_decoded_disclosure[digest].as_array().unwrap(); + match (claim_to_disclose, disclosure.get(1)) { + (Value::Array(claim_to_disclose), Some(Value::Array(sd_jwt_claims))) => { + hash_to_disclosure.append(&mut self.select_disclosures_from_disclosed_list(&sd_jwt_claims, claim_to_disclose)); + } + (Value::Object(claim_to_disclose), Some(Value::Object(sd_jwt_claims))) => { + hash_to_disclosure.push(self.sd_jwt_engine.hash_to_disclosure[digest].to_owned()); + hash_to_disclosure.append(&mut self.select_disclosures(&sd_jwt_claims, claim_to_disclose.to_owned())); + } + _ => {} + } + } else if let Some(claim_to_disclose) = claim_to_disclose.as_object() { + hash_to_disclosure.append(&mut self.select_disclosures(sd_jwt_claims, claim_to_disclose.to_owned())); + } + } + (Value::Array(claim_to_disclose), Value::Array(sd_jwt_claims)) => { + hash_to_disclosure.append(&mut self.select_disclosures_from_disclosed_list(sd_jwt_claims, claim_to_disclose)); } _ => {} } diff --git a/src/issuer.rs b/src/issuer.rs index 4392389..0107c51 100644 --- a/src/issuer.rs +++ b/src/issuer.rs @@ -72,21 +72,12 @@ impl<'a> SDJWTClaimsStrategy<'a> { str.strip_prefix(key).as_mut().and_then(|claim| { if let Some(next_claim) = claim.strip_prefix('.') { Some(next_claim) - } else if let Some(next_claim) = claim.strip_prefix('[').and_then(|str| str.strip_suffix(']')) { - Some(next_claim) } else { + // FIXME Replace to non-leackable impl // Removes "[", "]" symbols form "index" and returns "next_claim" as "index.remained_claims.." // For example: [0].street -> 0.street - if let Some(remainder) = claim.strip_prefix('[') { - *claim = remainder; - let remainder: Vec<&str> = claim.splitn(2, ']').collect(); - //FIXME Change to safe impl - *claim = remainder.join("").leak(); - - Some(claim) - } else { - None - } + *claim = claim.replace("[", "").replace("]","").leak(); + Some(claim) } }) }).collect(); diff --git a/src/lib.rs b/src/lib.rs index 43cb606..186efe0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,16 +12,16 @@ pub mod holder; pub mod issuer; pub mod verifier; -const DEFAULT_SIGNING_ALG: &str = "ES256"; +pub const DEFAULT_SIGNING_ALG: &str = "ES256"; const SD_DIGESTS_KEY: &str = "_sd"; const DIGEST_ALG_KEY: &str = "_sd_alg"; -const DEFAULT_DIGEST_ALG: &str = "sha-256"; +pub const DEFAULT_DIGEST_ALG: &str = "sha-256"; const SD_LIST_PREFIX: &str = "..."; const _SD_JWT_TYP_HEADER: &str = "sd+jwt"; const KB_JWT_TYP_HEADER: &str = "kb+jwt"; const JWS_KEY_DISCLOSURES: &str = "disclosures"; const JWS_KEY_KB_JWT: &str = "kb_jwt"; -const COMBINED_SERIALIZATION_FORMAT_SEPARATOR: &str = "~"; +pub const COMBINED_SERIALIZATION_FORMAT_SEPARATOR: &str = "~"; const JWT_SEPARATOR: &str = "."; #[derive(Debug)] diff --git a/src/verifier.rs b/src/verifier.rs index 26d64ae..1282d62 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -17,7 +17,7 @@ pub struct SDJWTVerifier { sd_jwt_payload: Map, _holder_public_key_payload: Option>, duplicate_hash_check: Vec, - verified_claims: Value, + pub verified_claims: Value, cb_get_issuer_key: Box, } diff --git a/tests/demos.rs b/tests/demos.rs index 6e7d858..8279e63 100644 --- a/tests/demos.rs +++ b/tests/demos.rs @@ -1,12 +1,16 @@ use crate::utils::fixtures::{ ADDRESS_CLAIMS, ADDRESS_ONLY_STRUCTURED_JSONPATH, ADDRESS_ONLY_STRUCTURED_ONE_OPEN_JSONPATH, - HOLDER_KEY, ISSUER_KEY, + ARRAYED_CLAIMS, ARRAYED_CLAIMS_JSONPATH, COMPLEX_EIDAS_CLAIMS, COMPLEX_EIDAS_JSONPATH, + HOLDER_KEY, ISSUER_KEY, ISSUER_PUBLIC_KEY, NESTED_ARRAY_CLAIMS, NESTED_ARRAY_JSONPATH, + W3C_VC_CLAIMS, W3C_VC_JSONPATH, }; -use jsonwebtoken::EncodingKey; +use jsonwebtoken::{DecodingKey, EncodingKey}; use rstest::{fixture, rstest}; -use serde_json::{json, Map, Value}; use sd_jwt_rs::issuer::SDJWTClaimsStrategy; -use sd_jwt_rs::{SDJWTHolder, SDJWTIssuer}; +use sd_jwt_rs::{SDJWTHolder, SDJWTIssuer, SDJWTVerifier}; +use sd_jwt_rs::{COMBINED_SERIALIZATION_FORMAT_SEPARATOR, DEFAULT_SIGNING_ALG}; +use serde_json::{json, Map, Value}; +use std::collections::HashSet; mod utils; @@ -16,6 +20,7 @@ fn issuer_key() -> EncodingKey { EncodingKey::from_ec_pem(private_issuer_bytes).unwrap() } +#[allow(unused)] fn holder_key() -> EncodingKey { let private_issuer_bytes = HOLDER_KEY.as_bytes(); EncodingKey::from_ec_pem(private_issuer_bytes).unwrap() @@ -26,95 +31,299 @@ fn _address_claims() -> serde_json::Value { } #[fixture] -fn address_flat<'a>() -> (serde_json::Value, SDJWTClaimsStrategy<'a>, Map) { +fn address_flat<'a>() -> ( + serde_json::Value, + SDJWTClaimsStrategy<'a>, + Map, + usize, +) { let value = _address_claims(); - (value.clone(), SDJWTClaimsStrategy::Flat, value.as_object().unwrap().clone()) + let number_of_revealed_sds = 1; + ( + value.clone(), + SDJWTClaimsStrategy::Flat, + value.as_object().unwrap().clone(), + number_of_revealed_sds, + ) } #[fixture] -fn address_full_recursive<'a>() -> (serde_json::Value, SDJWTClaimsStrategy<'a>, Map) { +fn address_full_recursive<'a>() -> ( + serde_json::Value, + SDJWTClaimsStrategy<'a>, + Map, + usize, +) { let value = _address_claims(); - let claims_to_disclose = json!({ - "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c", - "address": { - "locality": "Schulpforta", - "region": "Sachsen-Anhalt", - "country": "DE" - } - }).as_object().unwrap().clone(); - (value, SDJWTClaimsStrategy::Full, claims_to_disclose) + let claims_to_disclose = value.as_object().unwrap().clone(); + let number_of_revealed_sds = 5; + ( + value, + SDJWTClaimsStrategy::Full, + claims_to_disclose, + number_of_revealed_sds, + ) } #[fixture] -fn address_only_structured<'a>() -> (serde_json::Value, SDJWTClaimsStrategy<'a>, Map) { +fn address_only_structured<'a>() -> ( + serde_json::Value, + SDJWTClaimsStrategy<'a>, + Map, + usize, +) { let value = _address_claims(); - let claims_to_disclose = json!({ - "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c", - "address": { + let mut claims_to_disclose = value.clone(); + claims_to_disclose["address"] = json!({ + "street_address": "Schulstr. 12", "region": "Sachsen-Anhalt", "country": "DE" - } - }).as_object().unwrap().clone(); + }); + + let claims_to_disclose = claims_to_disclose.as_object().unwrap().clone(); + let number_of_revealed_sds = 3; ( - value, + value.clone(), SDJWTClaimsStrategy::Partial(ADDRESS_ONLY_STRUCTURED_JSONPATH.to_vec()), - claims_to_disclose + claims_to_disclose, + number_of_revealed_sds, ) } #[fixture] -fn address_only_structured_one_open<'a>() -> (serde_json::Value, SDJWTClaimsStrategy<'a>, Map) { +fn address_only_structured_one_open<'a>() -> ( + serde_json::Value, + SDJWTClaimsStrategy<'a>, + Map, + usize, +) { let value = _address_claims(); - let claims_to_disclose = json!({ - "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c", - "address": { + let mut claims_to_disclose = value.clone(); + claims_to_disclose["address"] = json!({ "region": "Sachsen-Anhalt", - } - }).as_object().unwrap().clone(); + "country": "DE" + }); + + let claims_to_disclose = claims_to_disclose.as_object().unwrap().clone(); + let number_of_revealed_sds = 1; ( value, SDJWTClaimsStrategy::Partial(ADDRESS_ONLY_STRUCTURED_ONE_OPEN_JSONPATH.to_vec()), - claims_to_disclose + claims_to_disclose, + number_of_revealed_sds, + ) +} + +#[fixture] +fn arrayed_claims<'a>() -> ( + serde_json::Value, + SDJWTClaimsStrategy<'a>, + Map, + usize, +) { + let value: serde_json::Value = serde_json::from_str(ARRAYED_CLAIMS).unwrap(); + let mut claims_to_disclose = value.clone(); + claims_to_disclose["addresses"] = json!([true, true]); + claims_to_disclose["nationalities"] = json!([false, true]); + + let claims_to_disclose = claims_to_disclose.as_object().unwrap().clone(); + let number_of_revealed_sds = 1; + + ( + value, + SDJWTClaimsStrategy::Partial(ARRAYED_CLAIMS_JSONPATH.to_vec()), + claims_to_disclose, + number_of_revealed_sds, + ) +} + +#[fixture] +fn nested_array<'a>() -> ( + serde_json::Value, + SDJWTClaimsStrategy<'a>, + Map, + usize, +) { + let value: serde_json::Value = serde_json::from_str(NESTED_ARRAY_CLAIMS).unwrap(); + let mut claims_to_disclose = value.clone(); + claims_to_disclose["nationalities"] = json!([[false, true]]); + + let claims_to_disclose = claims_to_disclose.as_object().unwrap().clone(); + let number_of_revealed_sds = 1; + + ( + value.clone(), + SDJWTClaimsStrategy::Partial(NESTED_ARRAY_JSONPATH.to_vec()), + claims_to_disclose, + number_of_revealed_sds, + ) +} + +#[fixture] +fn complex_eidas<'a>() -> ( + serde_json::Value, + SDJWTClaimsStrategy<'a>, + Map, + usize, +) { + let value: serde_json::Value = serde_json::from_str(COMPLEX_EIDAS_CLAIMS).unwrap(); + let mut claims_to_disclose = value.clone(); + claims_to_disclose["verified_claims"] = json!({ + "verification": { + "trust_framework": "eidas", + "assurance_level": "high", + "evidence": [ + { + "document": { + "type": "idcard", + "issuer": { + "name": "c_d612", + "country": "IT" + } + } + } + ] + }, + "claims": { + "place_of_birth": { + "country": "IT", + "locality": "Firenze" + }, + "nationalities": [ + "IT" + ] + } + }); + + let claims_to_disclose = claims_to_disclose.as_object().unwrap().clone(); + let number_of_revealed_sds = 5; + + ( + value.clone(), + SDJWTClaimsStrategy::Partial(COMPLEX_EIDAS_JSONPATH.to_vec()), + claims_to_disclose, + number_of_revealed_sds, ) } +#[fixture] +fn w3c_vc<'a>() -> ( + serde_json::Value, + SDJWTClaimsStrategy<'a>, + Map, + usize, +) { + let value: serde_json::Value = serde_json::from_str(W3C_VC_CLAIMS).unwrap(); + let mut claims_to_disclose = value.clone(); + claims_to_disclose["credentialSubject"] = json!({ + "email": "johndoe@example.com", + "address": { + "street_address": "123 Main St", + "locality": "Anytown", + "region": "Anystate", + "country": "US" + }, + "birthdate": "1940-01-01", + "is_over_18": true, + "is_over_21": true, + "is_over_65": true + }); + + let claims_to_disclose = claims_to_disclose.as_object().unwrap().clone(); + let number_of_revealed_sds = 6; + + ( + value.clone(), + SDJWTClaimsStrategy::Partial(W3C_VC_JSONPATH.to_vec()), + claims_to_disclose, + number_of_revealed_sds, + ) +} + +#[allow(unused)] +fn presentation_metadata() -> (Option, Option, Option) { + ( + Some("1234567890".to_owned()), + Some("https://verifier.example.org".to_owned()), + Some(holder_key()), + ) +} #[rstest] #[case(address_flat())] #[case(address_full_recursive())] #[case(address_only_structured())] #[case(address_only_structured_one_open())] -fn test_positive_cases( +#[case(arrayed_claims())] +#[case(nested_array())] +#[case(complex_eidas())] +#[case(w3c_vc())] +fn demo_positive_cases( issuer_key: EncodingKey, - #[case] data: (serde_json::Value, SDJWTClaimsStrategy, Map), - #[values(None)] holder_key: Option, + #[case] data: ( + serde_json::Value, + SDJWTClaimsStrategy, + Map, + usize, + ), + #[values((None, None, None), /*presentation_metadata()*/)] presentation_metadata: ( + Option, + Option, + Option, + ), #[values("compact".to_string())] format: String, - #[values(false)] add_decoy: bool, + #[values(None, Some(DEFAULT_SIGNING_ALG.to_owned()))] sign_algo: Option, + #[values(true, false)] add_decoy: bool, ) { - let (user_claims, strategy, holder_disclosed_claims) = data; + let (user_claims, strategy, holder_disclosed_claims, number_of_revealed_sds) = data; + let (nonce, aud, holder_key) = presentation_metadata; // Issuer issues SD-JWT - let issuer = SDJWTIssuer::issue_sd_jwt( - user_claims, strategy, issuer_key, holder_key, None, add_decoy, format.clone(), + let sd_jwt = SDJWTIssuer::issue_sd_jwt( + user_claims.clone(), + strategy, + issuer_key, + holder_key.clone(), + sign_algo.clone(), + add_decoy, + format.clone(), ); - println!("Issued SD-JWT \n {:#?}", issuer.sd_jwt_payload); + let issued = sd_jwt.serialized_sd_jwt.clone(); // Holder creates presentation - let holder = SDJWTHolder::new(issuer.serialized_sd_jwt.clone(), format); - let presentation = holder.create_presentation(holder_disclosed_claims, None, None, None, None); - println!("Holder created SD-JWT presentation \n {:#?}", presentation); -} - -#[test] -fn test_case_3() { - let issuer_key = issuer_key(); - let (user_claims, strategy, holder_disclosed_claims) = address_only_structured(); - // Issuer issues SD-JWT - let issuer = SDJWTIssuer::issue_sd_jwt( - user_claims, strategy, issuer_key, None, None, false, "compact".to_string(), + let holder = SDJWTHolder::new(sd_jwt.serialized_sd_jwt.clone(), format.clone()); + let presentation = holder.create_presentation( + holder_disclosed_claims, + nonce.clone(), + aud.clone(), + holder_key, + sign_algo, ); - println!("Issued SD-JWT \n {:#?}", issuer.sd_jwt_payload); - // Holder creates presentation - let holder = SDJWTHolder::new(issuer.serialized_sd_jwt.clone(), "compact".to_string()); - let presentation = holder.create_presentation(holder_disclosed_claims, None, None, None, None); - println!("Holder created SD-JWT presentation \n {:#?}", presentation); -} \ No newline at end of file + + let mut issued_parts: HashSet<&str> = issued + .split(COMBINED_SERIALIZATION_FORMAT_SEPARATOR) + .collect(); + issued_parts.remove(""); + + let mut revealed_parts: HashSet<&str> = presentation + .split(COMBINED_SERIALIZATION_FORMAT_SEPARATOR) + .collect(); + revealed_parts.remove(""); + + let intersected_parts: HashSet<_> = issued_parts.intersection(&revealed_parts).collect(); + // Compare that number of disclosed parts are equal + assert_eq!(intersected_parts.len(), revealed_parts.len()); + // here `+1` means adding issued jwt part also + assert_eq!(number_of_revealed_sds + 1, revealed_parts.len()); + // Verify presentation + let _verified = SDJWTVerifier::new( + presentation.clone(), + Box::new(|_, _| { + let public_issuer_bytes = ISSUER_PUBLIC_KEY.as_bytes(); + DecodingKey::from_ec_pem(public_issuer_bytes).unwrap() + }), + aud, + nonce, + format, + ) + .unwrap(); +} diff --git a/tests/utils/fixtures.rs b/tests/utils/fixtures.rs index 3b84226..ee43795 100644 --- a/tests/utils/fixtures.rs +++ b/tests/utils/fixtures.rs @@ -1,12 +1,16 @@ pub const ISSUER_KEY: &str = "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgUr2bNKuBPOrAaxsR\nnbSH6hIhmNTxSGXshDSUD1a1y7ihRANCAARvbx3gzBkyPDz7TQIbjF+ef1IsxUwz\nX1KWpmlVv+421F7+c1sLqGk4HUuoVeN8iOoAcE547pJhUEJyf5Asc6pP\n-----END PRIVATE KEY-----\n"; +pub const ISSUER_PUBLIC_KEY: &str = "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEb28d4MwZMjw8+00CG4xfnn9SLMVM\nM19SlqZpVb/uNtRe/nNbC6hpOB1LqFXjfIjqAHBOeO6SYVBCcn+QLHOqTw==\n-----END PUBLIC KEY-----\n"; pub const HOLDER_KEY: &str = "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg5K5SCos8zf9zRemG\nGUl6yfok+/NiiryNZsvANWMhF+KhRANCAARMIARHX1m+7c4cXiPhbi99JWgcg/Ug\nuKUOWzu8J4Z6Z2cY4llm2TEBh1VilUOIW0iIq7FX7nnAhOreI0/Rdh2U\n-----END PRIVATE KEY-----\n"; pub const ADDRESS_CLAIMS: &str = r#"{ - "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c", - "address": { - "street_address": "Schulstr. 12", - "locality": "Schulpforta", - "region": "Sachsen-Anhalt", - "country": "DE" + "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c", + "iss": "https://example.com/issuer", + "iat": 1683000000, + "exp": 1883000000, + "address": { + "street_address": "Schulstr. 12", + "locality": "Schulpforta", + "region": "Sachsen-Anhalt", + "country": "DE" } }"#; pub const ADDRESS_ONLY_STRUCTURED_JSONPATH: [&str; 4] = [ @@ -15,30 +19,76 @@ pub const ADDRESS_ONLY_STRUCTURED_JSONPATH: [&str; 4] = [ "$.address.region", "$.address.country", ]; - pub const ADDRESS_ONLY_STRUCTURED_ONE_OPEN_JSONPATH: [&str; 3] = [ "$.address.street_address", "$.address.locality", "$.address.region", ]; - +pub const ARRAYED_CLAIMS: &str = r#" +{ + "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c", + "iss": "https://example.com/issuer", + "iat": 1683000000, + "exp": 1883000000, + "addresses": [ + { + "street_address": "Schulstr. 12", + "locality": "Schulpforta", + "region": "Sachsen-Anhalt", + "country": "DE" + }, + { + "street_address": "456 Main St", + "locality": "Anytown", + "region": "NY", + "country": "US" + } + ], + "nationalities": [ + "US", + "CA" + ] +}"#; +pub const ARRAYED_CLAIMS_JSONPATH: [&str; 3] = [ + "$.addresses[1]", + "$.addresses[1].country", + "$.nationalities[0]", +]; +pub const NESTED_ARRAY_CLAIMS: &str = r#"{ + "iss": "https://example.com/issuer", + "iat": 1683000000, + "exp": 1883000000, + "nationalities": [ + ["IT", "UZ"], + ["DE", "US"] + ] +}"#; +pub const NESTED_ARRAY_JSONPATH: [&str; 3] = [ + "$.nationalities[0]", + "$.nationalities[0][0]", + "$.nationalities[0][1]", +]; pub const COMPLEX_EIDAS_CLAIMS: &str = r#"{ + "iss": "https://example.com/issuer", + "iat": 1683000000, + "exp": 1883000000, "verified_claims": { "verification": { "trust_framework": "eidas", "assurance_level": "high", "evidence": [ { - "type": "electronic_record", - "record": { - "type": "eu.europa.ec.eudiw.pid.1", - "source": { - "organization_name": "Comune di Firenze", - "organization_id": "c_d612", - "country_code": "IT", - "country": "Italy" + "type": "document", + "time": "2022-04-22T11:30Z", + "document": { + "type": "idcard", + "issuer": { + "name": "c_d612", + "country": "IT" }, - "personal_number": "9642-8fe652c8c040" + "number": "154554", + "date_of_issuance": "2021-03-23", + "date_of_expiry": "2031-03-22" } } ] @@ -70,218 +120,15 @@ pub const COMPLEX_EIDAS_JSONPATH: [&str; 7] = [ "$.verified_claims.claims.place_of_birth", "$.verified_claims.claims.nationalities", ]; -pub const COMPLEX_EIDAS_PROPOSAL_JSONPATH: [&str; 9] = [ - "$.verified_claims.verification.evidence[0].record.source", - "$.verified_claims.verification.evidence", - "$.verified_claims.claims.person_unique_identifier", - "$.verified_claims.claims.given_name", - "$.verified_claims.claims.family_name", - "$.verified_claims.claims.date_of_birth", - "$.verified_claims.claims.gender", - "$.verified_claims.claims.place_of_birth", - "$.verified_claims.claims.nationalities", -]; -pub const COMPLEX_EKYS_CLAIMS: &str = r#"{ - "verified_claims": { - "verification": { - "trust_framework": "de_aml", - "time": "2012-04-23T18:25Z", - "verification_process": "f24c6f-6d3f-4ec5-973e-b0d8506f3bc7", - "evidence": [ - { - "type": "document", - "method": "pipp", - "time": "2012-04-22T11:30Z", - "document": { - "type": "idcard", - "issuer": { - "name": "Stadt Augsburg", - "country": "DE" - }, - "number": "53554554", - "date_of_issuance": "2010-03-23", - "date_of_expiry": "2020-03-22" - } - } - ] - }, - "claims": { - "given_name": "Max", - "family_name": "Müller", - "nationalities": [ - "DE" - ], - "birthdate": "1956-01-28", - "place_of_birth": { - "country": "IS", - "locality": "Þykkvabæjarklaustur" - }, - "address": { - "locality": "Maxstadt", - "postal_code": "12344", - "country": "DE", - "street_address": "Weidenstraße 22" - } - } - }, - "birth_middle_name": "Timotheus", - "salutation": "Dr.", - "msisdn": "49123456789" -}"#; -pub const COMPLEX_EKUS_JSONPATH: [&str; 15] = [ - "$.msisdn", - "$.birth_middle_name", - "$.verified_claims.verification.time", - "$.verified_claims.verification.verification_process", - "$.verified_claims.verification.evidence[0].type", - "$.verified_claims.verification.evidence[0].method", - "$.verified_claims.verification.evidence[0].time", - "$.verified_claims.verification.evidence[0].document", - "$.verified_claims.claims.given_name", - "$.verified_claims.claims.family_name", - "$.verified_claims.claims.nationalities", - "$.verified_claims.claims.birthdate", - "$.verified_claims.claims.place_of_birth", - "$.verified_claims.claims.address", - "$.salutation", -]; -pub const SIMPLE_CLAIMS: &str = r#"{ - "sub": "john_doe_42", - "given_name": "John", - "family_name": "Doe", - "email": "johndoe@example.com", - "phone_number": "+1-202-555-0101", - "address": { - "street_address": "123 Main St", - "locality": "Anytown", - "region": "Anystate", - "country": "US" - }, - "birthdate": "1940-01-01" -}"#; -pub const SIMPLE_JSONPATH: [&str; 6] = [ - "$.birthdate", - "$.family_name", - "$.email", - "$.given_name", - "$.phone_number", - "$.address", -]; -pub const SIMPLE_STRUCTURED_JSONPATH: [&str; 10] = [ - "$.given_name", - "$.address.street_address", - "$.address.locality", - "$.address.region", - "$.address.country", - "$.birthdate", - "$.phone_number", - "$.family_name", - "$.email", - "$.sub", -]; -pub const SIMPLE_STRUCTURED_CLAIMS: &str = r#"{ - "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c", - "given_name": "太郎", - "family_name": "山田", - "email": "\"unusual email address\"@example.jp", - "phone_number": "+81-80-1234-5678", - "address": { - "street_address": "東京都港区芝公園4丁目2−8", - "locality": "東京都", - "region": "港区", - "country": "JP" - }, - "birthdate": "1940-01-01" -}"#; -pub const SIMPLE_JSON_SERIALIZATION_CLAIMS: &str = r#"{ - "sub": "john_doe_42", - "nationalities": [ - "US", - "CA", - "DE" - ], - "is_over": { - "13": true, - "18": false, - "21": false - }, - "addresses": [ - { - "street": "123 Main St", - "city": "Anytown", - "state": "NY", - "zip": "12345", - "type": "main_address" - }, - { - "street": "456 Main St", - "city": "Anytown", - "state": "NY", - "zip": "12345", - "type": "secondary_address" - } - ], - "null_values": [ - null, - null, - null, - null - ], - "data_types": [ - null, - 42, - 3.14, - "foo", - true, - [ - "Test" - ], - { - "foo": "bar" - } - ], - "nested_array": [ - [ - "foo", - "bar" - ], - [ - "baz", - "qux" - ] - ], - "array_with_recursive_sd": [ - "boring", - { - "foo": "bar", - "baz": { - "qux": "quux" - } - }, - [ - "foo", - "bar" - ] - ], - "sd_array": [ - 32, - 23 - ] -}"#; pub const W3C_VC_CLAIMS: &str = r#"{ "iss": "https://example.com", "jti": "http://example.com/credentials/3732", - "nbf": 1541493724, - "iat": 1541493724, + "iat": 1683000000, + "exp": 1883000000, "cnf": { "jwk": { "kty": "RSA", - "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbf - AAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMst - n64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_F - DW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n9 - 1CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHa - Q-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", + "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", "e": "AQAB" } }, @@ -303,7 +150,7 @@ pub const W3C_VC_CLAIMS: &str = r#"{ "is_over_65": true } }"#; -pub const SW3C_VC_JSONPATH: [&str; 9] = [ +pub const W3C_VC_JSONPATH: [&str; 9] = [ "$.credentialSubject.given_name", "$.credentialSubject.family_name", "$.credentialSubject.email", @@ -312,5 +159,5 @@ pub const SW3C_VC_JSONPATH: [&str; 9] = [ "$.credentialSubject.birthdate", "$.credentialSubject.is_over_18", "$.credentialSubject.is_over_21", - "$.credentialSubject.is_over_65", + "$.credentialSubject.is_over_65" ]; \ No newline at end of file