sd_jwt_rs/
verifier.rs

1// Copyright (c) 2024 DSR Corporation, Denver, Colorado.
2// https://www.dsr-corporation.com
3// SPDX-License-Identifier: Apache-2.0
4
5use crate::SDJWTSerializationFormat;
6use crate::error::Error;
7use crate::error::Result;
8use jsonwebtoken::jwk::Jwk;
9use jsonwebtoken::{Algorithm, DecodingKey, Header, Validation};
10use log::debug;
11use serde_json::{Map, Value};
12use std::ops::Add;
13use std::option::Option;
14use std::str::FromStr;
15use std::string::String;
16use std::vec::Vec;
17
18use crate::utils::base64_hash;
19use crate::{
20    SDJWTCommon, CNF_KEY, COMBINED_SERIALIZATION_FORMAT_SEPARATOR, DEFAULT_DIGEST_ALG,
21    DEFAULT_SIGNING_ALG, DIGEST_ALG_KEY, JWK_KEY, KB_DIGEST_KEY, KB_JWT_TYP_HEADER, SD_DIGESTS_KEY,
22    SD_LIST_PREFIX,
23};
24
25type KeyResolver = dyn Fn(&str, &Header) -> DecodingKey;
26
27pub struct SDJWTVerifier {
28    sd_jwt_engine: SDJWTCommon,
29
30    sd_jwt_payload: Map<String, Value>,
31    _holder_public_key_payload: Option<Map<String, Value>>,
32    duplicate_hash_check: Vec<String>,
33    pub verified_claims: Value,
34
35    cb_get_issuer_key: Box<KeyResolver>,
36}
37
38impl SDJWTVerifier {
39    /// Create a new SDJWTVerifier instance.
40    ///
41    /// # Arguments
42    /// * `sd_jwt_presentation` - The SD-JWT presentation to verify.
43    /// * `cb_get_issuer_key` - A callback function that takes the issuer and the header of the SD-JWT and returns the public key of the issuer.
44    /// * `expected_aud` - The expected audience of the SD-JWT.
45    /// * `expected_nonce` - The expected nonce of the SD-JWT.
46    /// * `serialization_format` - The serialization format of the SD-JWT, see [SDJWTSerializationFormat].
47    ///
48    /// # Returns
49    /// * `SDJWTVerifier` - The SDJWTVerifier instance. The verified claims can be accessed via the `verified_claims` property.
50    pub fn new(
51        sd_jwt_presentation: String,
52        cb_get_issuer_key: Box<KeyResolver>,
53        expected_aud: Option<String>,
54        expected_nonce: Option<String>,
55        serialization_format: SDJWTSerializationFormat,
56    ) -> Result<Self> {
57        let mut verifier = SDJWTVerifier {
58            sd_jwt_payload: serde_json::Map::new(),
59            _holder_public_key_payload: None,
60            duplicate_hash_check: Vec::new(),
61            cb_get_issuer_key,
62            sd_jwt_engine: SDJWTCommon {
63                serialization_format,
64                ..Default::default()
65            },
66            verified_claims: Value::Null,
67        };
68
69        verifier.sd_jwt_engine.parse_sd_jwt(sd_jwt_presentation)?;
70        verifier.sd_jwt_engine.create_hash_mappings()?;
71        let sign_alg = verifier.sd_jwt_engine.sign_alg.clone();
72        verifier.verify_sd_jwt(sign_alg.clone())?;
73        verifier.verified_claims = verifier.extract_sd_claims()?;
74
75        if let (Some(expected_aud), Some(expected_nonce)) = (&expected_aud, &expected_nonce) {
76            let sign_alg = verifier.sd_jwt_engine.unverified_input_key_binding_jwt
77                .as_ref()
78                .and_then(|value| {
79                    SDJWTCommon::decode_header_and_get_sign_algorithm(&value)
80                });
81
82            verifier.verify_key_binding_jwt(
83                expected_aud.to_owned(),
84                expected_nonce.to_owned(),
85                sign_alg.as_deref(),
86            )?;
87        } else if expected_aud.is_some() || expected_nonce.is_some() {
88            return Err(Error::InvalidInput(
89                "Either both expected_aud and expected_nonce must be provided or both must be None"
90                    .to_string(),
91            ));
92        }
93
94        Ok(verifier)
95    }
96
97    fn verify_sd_jwt(&mut self, sign_alg: Option<String>) -> Result<()> {
98        let sd_jwt = self
99            .sd_jwt_engine
100            .unverified_sd_jwt
101            .as_ref()
102            .ok_or(Error::ConversionError("reference".to_string()))?;
103        let parsed_header_sd_jwt = jsonwebtoken::decode_header(sd_jwt)
104            .map_err(|e| Error::DeserializationError(e.to_string()))?;
105
106        let unverified_issuer = self
107            .sd_jwt_engine
108            .unverified_input_sd_jwt_payload
109            .as_ref()
110            .ok_or(Error::ConversionError("reference".to_string()))?["iss"]
111            .as_str()
112            .ok_or(Error::ConversionError("str".to_string()))?;
113        let issuer_public_key = (self.cb_get_issuer_key)(unverified_issuer, &parsed_header_sd_jwt);
114        let algorithm: Algorithm = match sign_alg {
115            Some(alg_str) => Algorithm::from_str(&alg_str)
116                .map_err(|e| Error::DeserializationError(e.to_string()))?,
117            None => Algorithm::ES256, // Default or handle as needed
118        };
119        let claims = jsonwebtoken::decode(
120            sd_jwt,
121            &issuer_public_key,
122            &Validation::new(algorithm),
123        )
124            .map_err(|e| Error::DeserializationError(format!("Cannot decode jwt: {}", e)))?
125            .claims;
126
127        let _ = sign_alg; //FIXME check algo
128
129        self.sd_jwt_payload = claims;
130        self._holder_public_key_payload = self
131            .sd_jwt_payload
132            .get(CNF_KEY)
133            .and_then(Value::as_object)
134            .cloned();
135
136        Ok(())
137    }
138
139    fn verify_key_binding_jwt(
140        &mut self,
141        expected_aud: String,
142        expected_nonce: String,
143        sign_alg: Option<&str>,
144    ) -> Result<()> {
145        let sign_alg = sign_alg.unwrap_or(DEFAULT_SIGNING_ALG);
146        let holder_public_key_payload_jwk = match &self._holder_public_key_payload {
147            None => {
148                return Err(Error::KeyNotFound(
149                    "No holder public key in SD-JWT".to_string(),
150                ));
151            }
152            Some(payload) => {
153                if let Some(jwk) = payload.get(JWK_KEY) {
154                    jwk.clone()
155                } else {
156                    return Err(Error::InvalidInput("The holder_public_key_payload is malformed. It doesn't contain the claim jwk".to_string()));
157                }
158            }
159        };
160        let pubkey: DecodingKey = match serde_json::from_value::<Jwk>(holder_public_key_payload_jwk)
161        {
162            Ok(jwk) => {
163                if let Ok(pubkey) = DecodingKey::from_jwk(&jwk) {
164                    pubkey
165                } else {
166                    return Err(Error::DeserializationError(
167                        "Cannot parse DecodingKey from json".to_string(),
168                    ));
169                }
170            }
171            Err(_) => {
172                return Err(Error::DeserializationError(
173                    "Cannot parse JWK from json".to_string(),
174                ));
175            }
176        };
177        let key_binding_jwt = match &self.sd_jwt_engine.unverified_input_key_binding_jwt {
178            Some(payload) => {
179                let mut validation = Validation::new(
180                    Algorithm::from_str(sign_alg)
181                        .map_err(|e| Error::DeserializationError(e.to_string()))?,
182                );
183                validation.set_audience(&[expected_aud.as_str()]);
184                validation.set_required_spec_claims(&["aud"]);
185
186                jsonwebtoken::decode::<Map<String, Value>>(payload.as_str(), &pubkey, &validation)
187                    .map_err(|e| Error::DeserializationError(e.to_string()))?
188            }
189            None => {
190                return Err(Error::InvalidState(
191                    "Cannot take Key Binding JWK from String".to_string(),
192                ));
193            }
194        };
195        if key_binding_jwt.header.typ != Some(KB_JWT_TYP_HEADER.to_string()) {
196            return Err(Error::InvalidInput("Invalid header type".to_string()));
197        }
198        if key_binding_jwt.claims.get("nonce") != Some(&Value::String(expected_nonce)) {
199            return Err(Error::InvalidInput("Invalid nonce".to_string()));
200        }
201        if self.sd_jwt_engine.serialization_format == SDJWTSerializationFormat::Compact {
202            let sd_hash = self._get_key_binding_digest_hash()?;
203            if key_binding_jwt.claims.get(KB_DIGEST_KEY) != Some(&Value::String(sd_hash)) {
204                return Err(Error::InvalidInput("Invalid digest in KB-JWT".to_string()));
205            }
206        }
207
208        Ok(())
209    }
210
211    fn _get_key_binding_digest_hash(&mut self) -> Result<String> {
212        let mut combined: Vec<&str> =
213            Vec::with_capacity(self.sd_jwt_engine.input_disclosures.len() + 1);
214        combined.push(
215            self.sd_jwt_engine
216                .unverified_sd_jwt
217                .as_ref()
218                .ok_or(Error::ConversionError("reference".to_string()))?
219                .as_str(),
220        );
221        combined.extend(
222            self.sd_jwt_engine
223                .input_disclosures
224                .iter()
225                .map(|s| s.as_str()),
226        );
227        let combined = combined
228            .join(COMBINED_SERIALIZATION_FORMAT_SEPARATOR)
229            .add(COMBINED_SERIALIZATION_FORMAT_SEPARATOR);
230
231        Ok(base64_hash(combined.as_bytes()))
232    }
233
234    fn extract_sd_claims(&mut self) -> Result<Value> {
235        if self.sd_jwt_payload.contains_key(DIGEST_ALG_KEY)
236            && self.sd_jwt_payload[DIGEST_ALG_KEY] != DEFAULT_DIGEST_ALG
237        {
238            return Err(Error::DeserializationError(format!(
239                "Invalid hash algorithm {}",
240                self.sd_jwt_payload[DIGEST_ALG_KEY]
241            )));
242        }
243
244        self.duplicate_hash_check = Vec::new();
245        let claims: Value = self.sd_jwt_payload.clone().into_iter().collect();
246        self.unpack_disclosed_claims(&claims)
247    }
248
249    fn unpack_disclosed_claims(&mut self, sd_jwt_claims: &Value) -> Result<Value> {
250        match sd_jwt_claims {
251            Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => {
252                Ok(sd_jwt_claims.to_owned())
253            }
254            Value::Array(arr) => {
255                self.unpack_disclosed_claims_in_array(arr)
256            }
257            Value::Object(obj) => {
258                self.unpack_disclosed_claims_in_object(obj)
259            }
260        }
261    }
262
263    fn unpack_disclosed_claims_in_array(&mut self, arr: &Vec<Value>) -> Result<Value> {
264        if arr.is_empty() {
265            return Err(Error::InvalidArrayDisclosureObject(
266                "Array of disclosed claims cannot be empty".to_string(),
267            ));
268        }
269
270        let mut claims = vec![];
271        for value in arr {
272
273            match value {
274                // case for SD objects in arrays
275                Value::Object(obj) if obj.contains_key(SD_LIST_PREFIX) => {
276                    if obj.len() > 1 {
277                        return Err(Error::InvalidDisclosure(
278                            "Disclosed claim object in an array maust contain only one key".to_string(),
279                        ));
280                    }
281
282                    let digest = obj.get(SD_LIST_PREFIX).unwrap();
283                    let disclosed_claim = self.unpack_from_digest(digest)?;
284                    if let Some(disclosed_claim) = disclosed_claim {
285                        claims.push(disclosed_claim);
286                    }
287                },
288                _ => {
289                    let claim = self.unpack_disclosed_claims(value)?;
290                    claims.push(claim);
291                },
292            }
293        }
294        Ok(Value::Array(claims))
295    }
296
297    fn unpack_disclosed_claims_in_object(&mut self, nested_sd_jwt_claims: &Map<String, Value>) -> Result<Value> {
298        let mut disclosed_claims: Map<String, Value> = serde_json::Map::new();
299
300        for (key, value) in nested_sd_jwt_claims {
301            if key != SD_DIGESTS_KEY && key != DIGEST_ALG_KEY {
302                disclosed_claims.insert(key.to_owned(), self.unpack_disclosed_claims(value)?);
303            }
304        }
305
306        if let Some(Value::Array(digest_of_disclosures)) = nested_sd_jwt_claims.get(SD_DIGESTS_KEY)
307        {
308            self.unpack_from_digests(&mut disclosed_claims, digest_of_disclosures)?;
309        }
310
311        Ok(Value::Object(disclosed_claims))
312    }
313
314    fn unpack_from_digests(
315        &mut self,
316        pre_output: &mut Map<String, Value>,
317        digests_of_disclosures: &Vec<Value>,
318    ) -> Result<()> {
319        for digest in digests_of_disclosures {
320            let digest = digest
321                .as_str()
322                .ok_or(Error::ConversionError("str".to_string()))?;
323            if self.duplicate_hash_check.contains(&digest.to_string()) {
324                return Err(Error::DuplicateDigestError(digest.to_string()));
325            }
326            self.duplicate_hash_check.push(digest.to_string());
327
328            if let Some(value_for_digest) =
329                self.sd_jwt_engine.hash_to_decoded_disclosure.get(digest)
330            {
331                let disclosure =
332                    value_for_digest
333                        .as_array()
334                        .ok_or(Error::InvalidArrayDisclosureObject(
335                            value_for_digest.to_string(),
336                        ))?;
337                let key = disclosure[1]
338                    .as_str()
339                    .ok_or(Error::ConversionError("str".to_string()))?
340                    .to_owned();
341                let value = disclosure[2].clone();
342                if pre_output.contains_key(&key) {
343                    return Err(Error::DuplicateKeyError(key.to_string()));
344                }
345                let unpacked_value = self.unpack_disclosed_claims(&value)?;
346                pre_output.insert(key, unpacked_value);
347            } else {
348                debug!("Digest {:?} skipped as decoy", digest)
349            }
350        }
351
352        Ok(())
353    }
354
355    fn unpack_from_digest(
356        &mut self,
357        digest: &Value,
358    ) -> Result<Option<Value>> {
359        let digest = digest
360            .as_str()
361            .ok_or(Error::ConversionError("str".to_string()))?;
362        if self.duplicate_hash_check.contains(&digest.to_string()) {
363            return Err(Error::DuplicateDigestError(digest.to_string()));
364        }
365        self.duplicate_hash_check.push(digest.to_string());
366
367        if let Some(value_for_digest) =
368            self.sd_jwt_engine.hash_to_decoded_disclosure.get(digest)
369        {
370            let disclosure =
371                value_for_digest
372                    .as_array()
373                    .ok_or(Error::InvalidArrayDisclosureObject(
374                        value_for_digest.to_string(),
375                    ))?;
376
377            let value = disclosure[1].clone();
378            let unpacked_value = self.unpack_disclosed_claims(&value)?;
379            return Ok(Some(unpacked_value));
380        } else {
381            debug!("Digest {:?} skipped as decoy", digest)
382        }
383
384        Ok(None)
385    }
386}
387
388#[cfg(test)]
389mod tests {
390    use crate::issuer::ClaimsForSelectiveDisclosureStrategy;
391    use crate::{SDJWTHolder, SDJWTIssuer, SDJWTVerifier, SDJWTSerializationFormat};
392    use jsonwebtoken::{DecodingKey, EncodingKey};
393    use serde_json::{json, Value};
394
395    const PRIVATE_ISSUER_PEM: &str = "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgUr2bNKuBPOrAaxsR\nnbSH6hIhmNTxSGXshDSUD1a1y7ihRANCAARvbx3gzBkyPDz7TQIbjF+ef1IsxUwz\nX1KWpmlVv+421F7+c1sLqGk4HUuoVeN8iOoAcE547pJhUEJyf5Asc6pP\n-----END PRIVATE KEY-----\n";
396    const PUBLIC_ISSUER_PEM: &str = "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEb28d4MwZMjw8+00CG4xfnn9SLMVM\nM19SlqZpVb/uNtRe/nNbC6hpOB1LqFXjfIjqAHBOeO6SYVBCcn+QLHOqTw==\n-----END PUBLIC KEY-----\n";
397    const PRIVATE_ISSUER_ED25519_PEM: &str = "-----BEGIN PRIVATE KEY-----\nMFECAQEwBQYDK2VwBCIEIF93k6rxZ8W38cm0rOwfGdH+YY3k10hP+7gd0falPLg0\ngSEAdW31QyWzfed4EPcw1rYuUa1QU+fXEL0HhdAfYZRkihc=\n-----END PRIVATE KEY-----\n";
398    const PUBLIC_ISSUER_ED25519_PEM: &str = "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAdW31QyWzfed4EPcw1rYuUa1QU+fXEL0HhdAfYZRkihc=\n-----END PUBLIC KEY-----\n";
399
400    // EdDSA (Ed25519)
401    const HOLDER_KEY_ED25519: &str = "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIOeIDnHHMoPCUTiq206gR+FdCdNtc31SzF1nKX31hvhd\n-----END PRIVATE KEY-----";
402
403    const HOLDER_JWK_KEY_ED25519: &str = r#"{
404        "alg": "EdDSA",
405        "crv": "Ed25519",
406        "kid": "52128f2e-900e-414e-81c3-0b5f86f0f7b3",
407        "kty": "OKP",
408        "x": "24QLWXJ18wtbg3k_MDGhGM17Xh39UftuxbwJZzRLzkA"
409    }"#;
410
411    #[test]
412    fn verify_full_presentation() {
413        let user_claims = json!({
414            "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c",
415            "iss": "https://example.com/issuer",
416            "iat": 1683000000,
417            "exp": 1883000000,
418            "address": {
419                "street_address": "Schulstr. 12",
420                "locality": "Schulpforta",
421                "region": "Sachsen-Anhalt",
422                "country": "DE"
423            }
424        });
425        let private_issuer_bytes = PRIVATE_ISSUER_PEM.as_bytes();
426        let issuer_key = EncodingKey::from_ec_pem(private_issuer_bytes).unwrap();
427        let sd_jwt = SDJWTIssuer::new(issuer_key, None).issue_sd_jwt(
428            user_claims.clone(),
429            ClaimsForSelectiveDisclosureStrategy::AllLevels,
430            None,
431            false,
432            SDJWTSerializationFormat::Compact,
433        )
434            .unwrap();
435        let presentation = SDJWTHolder::new(sd_jwt.clone(), SDJWTSerializationFormat::Compact)
436            .unwrap()
437            .create_presentation(
438                user_claims.as_object().unwrap().clone(),
439                None,
440                None,
441                None,
442                None,
443            )
444            .unwrap();
445        assert_eq!(sd_jwt, presentation);
446        let verified_claims = SDJWTVerifier::new(
447            presentation,
448            Box::new(|_, _| {
449                let public_issuer_bytes = PUBLIC_ISSUER_PEM.as_bytes();
450                DecodingKey::from_ec_pem(public_issuer_bytes).unwrap()
451            }),
452            None,
453            None,
454            SDJWTSerializationFormat::Compact,
455        )
456            .unwrap()
457            .verified_claims;
458        assert_eq!(user_claims, verified_claims);
459    }
460
461    #[test]
462    fn verify_noclaim_presentation() {
463        let user_claims = json!({
464            "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c",
465            "iss": "https://example.com/issuer",
466            "iat": 1683000000,
467            "exp": 1883000000,
468            "address": {
469                "street_address": "Schulstr. 12",
470                "locality": "Schulpforta",
471                "region": "Sachsen-Anhalt",
472                "country": "DE"
473            }
474        });
475        let private_issuer_bytes = PRIVATE_ISSUER_PEM.as_bytes();
476        let issuer_key = EncodingKey::from_ec_pem(private_issuer_bytes).unwrap();
477        let sd_jwt = SDJWTIssuer::new(issuer_key, None).issue_sd_jwt(
478            user_claims.clone(),
479            ClaimsForSelectiveDisclosureStrategy::NoSDClaims,
480            None,
481            false,
482            SDJWTSerializationFormat::Compact,
483        )
484            .unwrap();
485
486        let presentation = SDJWTHolder::new(sd_jwt.clone(), SDJWTSerializationFormat::Compact)
487            .unwrap()
488            .create_presentation(
489                user_claims.as_object().unwrap().clone(),
490                None,
491                None,
492                None,
493                None,
494            )
495            .unwrap();
496        assert_eq!(sd_jwt, presentation);
497        let verified_claims = SDJWTVerifier::new(
498            presentation,
499            Box::new(|_, _| {
500                let public_issuer_bytes = PUBLIC_ISSUER_PEM.as_bytes();
501                DecodingKey::from_ec_pem(public_issuer_bytes).unwrap()
502            }),
503            None,
504            None,
505            SDJWTSerializationFormat::Compact,
506        )
507            .unwrap()
508            .verified_claims;
509        assert_eq!(user_claims, verified_claims);
510    }
511
512    #[test]
513    fn verify_arrayed_presentation() {
514        let user_claims = json!(
515            {
516              "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c",
517              "name": "Bois",
518              "iss": "https://example.com/issuer",
519              "iat": 1683000000,
520              "exp": 1883000000,
521              "addresses": [
522                {
523                "street_address": "Schulstr. 12",
524                "locality": "Schulpforta",
525                "region": "Sachsen-Anhalt",
526                "country": "DE"
527                },
528                {
529                "street_address": "456 Main St",
530                "locality": "Anytown",
531                "region": "NY",
532                "country": "US"
533                }
534              ],
535              "nationalities": [
536                "US",
537                "CA"
538              ]
539            }
540        );
541        let private_issuer_bytes = PRIVATE_ISSUER_PEM.as_bytes();
542        let issuer_key = EncodingKey::from_ec_pem(private_issuer_bytes).unwrap();
543        let strategy = ClaimsForSelectiveDisclosureStrategy::Custom(vec![
544            "$.name",
545            "$.addresses[1]",
546            "$.addresses[1].country",
547            "$.nationalities[0]",
548        ]);
549        let sd_jwt = SDJWTIssuer::new(issuer_key, None).issue_sd_jwt(
550            user_claims.clone(),
551            strategy,
552            None,
553            false,
554            SDJWTSerializationFormat::Compact,
555        )
556            .unwrap();
557
558        let mut claims_to_disclose = user_claims.clone();
559        claims_to_disclose["addresses"] = Value::Array(vec![Value::Bool(true), Value::Bool(true)]);
560        claims_to_disclose["nationalities"] =
561            Value::Array(vec![Value::Bool(true), Value::Bool(true)]);
562        let presentation = SDJWTHolder::new(sd_jwt, SDJWTSerializationFormat::Compact)
563            .unwrap()
564            .create_presentation(
565                claims_to_disclose.as_object().unwrap().clone(),
566                None,
567                None,
568                None,
569                None,
570            )
571            .unwrap();
572
573        let verified_claims = SDJWTVerifier::new(
574            presentation.clone(),
575            Box::new(|_, _| {
576                let public_issuer_bytes = PUBLIC_ISSUER_PEM.as_bytes();
577                DecodingKey::from_ec_pem(public_issuer_bytes).unwrap()
578            }),
579            None,
580            None,
581            SDJWTSerializationFormat::Compact,
582        )
583            .unwrap()
584            .verified_claims;
585
586        let expected_verified_claims = json!(
587            {
588                "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c",
589                "addresses": [
590                    {
591                        "street_address": "Schulstr. 12",
592                        "locality": "Schulpforta",
593                        "region": "Sachsen-Anhalt",
594                        "country": "DE",
595                    },
596                    {
597                        "street_address": "456 Main St",
598                        "locality": "Anytown",
599                        "region": "NY",
600                    },
601                ],
602                "nationalities": [
603                    "US",
604                    "CA",
605                ],
606                "iss": "https://example.com/issuer",
607                "iat": 1683000000,
608                "exp": 1883000000,
609                "name": "Bois"
610            }
611        );
612
613        assert_eq!(verified_claims, expected_verified_claims);
614    }
615
616    #[test]
617    fn verify_arrayed_no_sd_presentation() {
618        let user_claims = json!(
619            {
620                "iss": "https://example.com/issuer",
621                "iat": 1683000000,
622                "exp": 1883000000,
623                "array_with_recursive_sd": [
624                    "boring",
625                    {
626                        "foo": "bar",
627                        "baz": {
628                            "qux": "quux"
629                        }
630                    },
631                    ["foo", "bar"]
632                ],
633                "test2": ["foo", "bar"]
634            }
635        );
636        let private_issuer_bytes = PRIVATE_ISSUER_PEM.as_bytes();
637        let issuer_key = EncodingKey::from_ec_pem(private_issuer_bytes).unwrap();
638        let strategy = ClaimsForSelectiveDisclosureStrategy::Custom(vec![
639            "$.array_with_recursive_sd[1]",
640            "$.array_with_recursive_sd[1].baz",
641            "$.array_with_recursive_sd[2][0]",
642            "$.array_with_recursive_sd[2][1]",
643            "$.test2[0]",
644            "$.test2[1]",
645        ]);
646        let sd_jwt = SDJWTIssuer::new(issuer_key, None).issue_sd_jwt(
647            user_claims.clone(),
648            strategy,
649            None,
650            false,
651            SDJWTSerializationFormat::Compact,
652        )
653            .unwrap();
654
655        let claims_to_disclose = json!({});
656
657        let presentation = SDJWTHolder::new(sd_jwt, SDJWTSerializationFormat::Compact)
658            .unwrap()
659            .create_presentation(
660                claims_to_disclose.as_object().unwrap().clone(),
661                None,
662                None,
663                None,
664                None,
665            )
666            .unwrap();
667
668        let verified_claims = SDJWTVerifier::new(
669            presentation.clone(),
670            Box::new(|_, _| {
671                let public_issuer_bytes = PUBLIC_ISSUER_PEM.as_bytes();
672                DecodingKey::from_ec_pem(public_issuer_bytes).unwrap()
673            }),
674            None,
675            None,
676            SDJWTSerializationFormat::Compact,
677        )
678            .unwrap()
679            .verified_claims;
680
681        let expected_verified_claims = json!(
682            {
683                "iss": "https://example.com/issuer",
684                "iat": 1683000000,
685                "exp": 1883000000,
686                "array_with_recursive_sd":  [
687                    "boring",
688                    [],
689                ],
690                "test2": [],
691            }
692        );
693
694        assert_eq!(verified_claims, expected_verified_claims);
695    }
696
697    #[test]
698    fn verify_full_presentation_to_allow_other_algorithms_json_format() {
699
700        let user_claims = json!({
701            "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c",
702            "iss": "https://example.com/issuer",
703            "iat": 1683000000,
704            "exp": 1883000000,
705            "address": {
706                "street_address": "Schulstr. 12",
707                "locality": "Schulpforta",
708                "region": "Sachsen-Anhalt",
709                "country": "DE"
710            }
711        });
712        let private_issuer_bytes = PRIVATE_ISSUER_ED25519_PEM.as_bytes();
713        let issuer_key = EncodingKey::from_ed_pem(private_issuer_bytes).unwrap();
714        let sd_jwt = SDJWTIssuer::new(issuer_key, Some("EdDSA".to_string())).issue_sd_jwt(
715            user_claims.clone(),
716            ClaimsForSelectiveDisclosureStrategy::AllLevels,
717            None,
718            false,
719            SDJWTSerializationFormat::JSON, // Changed to Json format
720        )
721            .unwrap();
722       
723        let presentation = SDJWTHolder::new(sd_jwt.clone(), SDJWTSerializationFormat::JSON) // Changed to Json format
724            .unwrap()
725            .create_presentation(
726                user_claims.as_object().unwrap().clone(),
727                None,
728                None,
729                None,
730                None
731            )
732            .unwrap();
733        assert_eq!(sd_jwt, presentation);
734        let verified_claims = SDJWTVerifier::new(
735            presentation,
736            Box::new(|_, _| {
737                let public_issuer_bytes = PUBLIC_ISSUER_ED25519_PEM.as_bytes();
738                DecodingKey::from_ed_pem(public_issuer_bytes).unwrap()
739            }),
740            None,
741            None,
742            SDJWTSerializationFormat::JSON, // Changed to Json format
743        )
744            .unwrap()
745            .verified_claims;
746        assert_eq!(user_claims, verified_claims);
747    }
748    #[test]
749    fn verify_presentation_when_sd_jwt_uses_es256_and_key_binding_uses_eddsa() {
750
751        let user_claims = json!({
752            "address": {
753                "street_address": "Schulstr. 12",
754                "locality": "Schulpforta",
755                "region": "Sachsen-Anhalt",
756                "country": "DE"
757            },
758            "exp": 1883000000,
759            "iat": 1683000000,
760            "iss": "https://example.com/issuer",
761            "sub": "6c5c0a49-b589-431d-bae7-219122a9ec2c",
762
763        });
764
765        let private_issuer_bytes = PRIVATE_ISSUER_PEM.as_bytes();
766        let issuer_key = EncodingKey::from_ec_pem(private_issuer_bytes).unwrap();
767
768        let mut issuer = SDJWTIssuer::new(issuer_key, Some("ES256".to_string()));
769
770        let sd_jwt = issuer.issue_sd_jwt(
771            user_claims.clone(),
772            ClaimsForSelectiveDisclosureStrategy::AllLevels,
773            Some(serde_json::from_str(HOLDER_JWK_KEY_ED25519).unwrap()),
774            false,
775            SDJWTSerializationFormat::JSON, // Changed to Json format
776        ).unwrap();
777
778        let private_holder_bytes = HOLDER_KEY_ED25519.as_bytes();
779        let holder_key = EncodingKey::from_ed_pem(private_holder_bytes).unwrap();
780
781        let nonce = Some(String::from("testNonce"));
782        let aud = Some(String::from("testAud"));
783
784        let mut holder = SDJWTHolder::new(sd_jwt.clone(), SDJWTSerializationFormat::JSON).unwrap(); // Changed to Json format
785        let presentation = holder.create_presentation(
786                user_claims.as_object().unwrap().clone(),
787                nonce.clone(),
788                aud.clone(),
789                Some(holder_key),
790                Some("EdDSA".to_string())
791            )
792            .unwrap();
793        let verified_claims = SDJWTVerifier::new(
794            presentation,
795            Box::new(|_, _| {
796                let public_issuer_bytes = PUBLIC_ISSUER_PEM.as_bytes();
797                DecodingKey::from_ec_pem(public_issuer_bytes).unwrap()
798            }),
799            aud.clone(),
800            nonce.clone(),
801            SDJWTSerializationFormat::JSON, // Changed to Json format
802        )
803            .unwrap()
804            .verified_claims;
805
806        let claims_to_check = json!({
807            "iss": user_claims["iss"].clone(),
808            "iat": user_claims["iat"].clone(),
809            "exp": user_claims["exp"].clone(),
810            "cnf": {
811                "jwk": serde_json::from_str::<Value>(HOLDER_JWK_KEY_ED25519).unwrap(),
812            },
813            "sub": user_claims["sub"].clone(),
814            "address": user_claims["address"].clone(),
815        });
816
817        assert_eq!(claims_to_check, verified_claims);
818    }
819}