Skip to content

Commit

Permalink
Fix data url overflow issue in iref.
Browse files Browse the repository at this point in the history
  • Loading branch information
timothee-haudebourg committed Jul 25, 2024
1 parent a1c1034 commit 94ef9c2
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ async-std = "1.9"
async-trait = "0.1.68"
thiserror = "1.0.40"
chrono = "0.4.24"
iref = "3.2.1"
iref = "3.2.2"
static-iref = "3.0"
rdf-types = "0.22.3"
xsd-types = "0.9.4"
Expand Down
10 changes: 7 additions & 3 deletions crates/claims/crates/jws/src/compact/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ use std::{borrow::Cow, ops::Deref};
pub struct CompactJWS([u8]);

impl CompactJWS {
pub fn new(data: &[u8]) -> Result<&Self, InvalidCompactJWS<&[u8]>> {
if Self::check(data) {
Ok(unsafe { Self::new_unchecked(data) })
pub fn new<T>(data: &T) -> Result<&Self, InvalidCompactJWS<&T>>
where
T: ?Sized + AsRef<[u8]>,
{
let bytes = data.as_ref();
if Self::check(bytes) {
Ok(unsafe { Self::new_unchecked(bytes) })
} else {
Err(InvalidCompactJWS(data))
}
Expand Down
7 changes: 6 additions & 1 deletion crates/claims/crates/vc-jose-cose/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ ssi-json-ld.workspace = true
xsd-types.workspace = true
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
thiserror.workspace = true

[dev-dependencies]
ssi-jws = { workspace = true, features = ["secp256r1"] }
ssi-jwk.workspace = true
async-std.workspace = true
64 changes: 62 additions & 2 deletions crates/claims/crates/vc-jose-cose/src/jose/credential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::JoseDecodeError;
use serde::{de::DeserializeOwned, Serialize};
use ssi_claims_core::{ClaimsValidity, DateTimeProvider, SignatureError, ValidateClaims};
use ssi_json_ld::{iref::Uri, syntax::Context};
use ssi_jws::{CompactJWS, DecodedJWS, JWSPayload, JWSSigner};
use ssi_jws::{CompactJWS, DecodedJWS, JWSPayload, JWSSigner, ValidateJWSHeader};
use ssi_vc::{
enveloped::EnvelopedVerifiableCredential,
v2::{Credential, CredentialTypes, JsonCredential},
Expand All @@ -24,7 +24,7 @@ impl<T: Serialize> JoseVc<T> {
let jws = JWSPayload::sign(self, signer).await?;
Ok(EnvelopedVerifiableCredential {
context: Context::iri_ref(ssi_vc::v2::CREDENTIALS_V2_CONTEXT_IRI.to_owned().into()),
id: format!("data:application/vc-ld+jwt;{jws}").parse().unwrap(),
id: format!("data:application/vc-ld+jwt,{jws}").parse().unwrap(),
})
}
}
Expand Down Expand Up @@ -59,6 +59,14 @@ impl<T: Serialize> JWSPayload for JoseVc<T> {
}
}

impl<E, T> ValidateJWSHeader<E> for JoseVc<T> {
fn validate_jws_header(&self, _env: &E, _header: &ssi_jws::Header) -> ClaimsValidity {
// There are no formal obligations about `typ` and `cty`.
// It SHOULD be `vc-ld+jwt` and `vc`, but it does not MUST.
Ok(())
}
}

impl<T: MaybeIdentified> MaybeIdentified for JoseVc<T> {
fn id(&self) -> Option<&Uri> {
self.0.id()
Expand Down Expand Up @@ -149,3 +157,55 @@ impl<E, P, T: ValidateClaims<E, P>> ValidateClaims<E, P> for JoseVc<T> {
self.0.validate_claims(environment, proof)
}
}

#[cfg(test)]
mod tests {
use serde_json::json;
use ssi_claims_core::VerificationParameters;
use ssi_jwk::JWK;
use ssi_jws::{CompactJWS, CompactJWSBuf};
use ssi_vc::v2::JsonCredential;

use crate::JoseVc;

async fn verify(input: &CompactJWS, key: &JWK) {
let vc = JoseVc::decode_any(input).unwrap();
let params = VerificationParameters::from_resolver(key);
let result = vc.verify(params).await.unwrap();
assert_eq!(result, Ok(()))
}

#[async_std::test]
async fn jose_vc_roundtrip() {
let vc: JsonCredential = serde_json::from_value(json!({
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"id": "http://university.example/credentials/1872",
"type": [
"VerifiableCredential",
"ExampleAlumniCredential"
],
"issuer": "https://university.example/issuers/565049",
"validFrom": "2010-01-01T19:23:24Z",
"credentialSchema": {
"id": "https://example.org/examples/degree.json",
"type": "JsonSchema"
},
"credentialSubject": {
"id": "did:example:123",
"degree": {
"type": "BachelorDegree",
"name": "Bachelor of Science and Arts"
}
}
}))
.unwrap();

let key = JWK::generate_p256();
let enveloped = JoseVc(vc).sign_into_enveloped(&key).await.unwrap();
let jws = CompactJWSBuf::new(enveloped.id.decoded_data().unwrap().into_owned()).unwrap();
verify(&jws, &key).await
}
}
63 changes: 58 additions & 5 deletions crates/claims/crates/vc-jose-cose/src/jose/presentation.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
use super::JoseDecodeError;
use serde::{de::DeserializeOwned, Serialize};
use ssi_claims_core::SignatureError;
use ssi_claims_core::{ClaimsValidity, SignatureError, ValidateClaims};
use ssi_json_ld::{iref::Uri, syntax::Context};
use ssi_jws::{CompactJWS, DecodedJWS, JWSPayload, JWSSigner};
use ssi_jws::{CompactJWS, DecodedJWS, JWSPayload, JWSSigner, ValidateJWSHeader};
use ssi_vc::{
enveloped::EnvelopedVerifiablePresentation,
enveloped::{EnvelopedVerifiableCredential, EnvelopedVerifiablePresentation},
v2::{syntax::JsonPresentation, Presentation, PresentationTypes},
MaybeIdentified,
};
use std::borrow::Cow;

/// Payload of a JWS-secured Verifiable Presentation.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct JoseVp<T = JsonPresentation>(pub T);
pub struct JoseVp<T = JsonPresentation<EnvelopedVerifiableCredential>>(pub T);

impl<T: Serialize> JWSPayload for JoseVp<T> {
fn typ(&self) -> Option<&str> {
Expand All @@ -28,6 +28,14 @@ impl<T: Serialize> JWSPayload for JoseVp<T> {
}
}

impl<E, T> ValidateJWSHeader<E> for JoseVp<T> {
fn validate_jws_header(&self, _env: &E, _header: &ssi_jws::Header) -> ClaimsValidity {
// There are no formal obligations about `typ` and `cty`.
// It SHOULD be `vp-ld+jwt` and `vp`, but it does not MUST.
Ok(())
}
}

impl<T: Serialize> JoseVp<T> {
/// Sign a JOSE VC into an enveloped verifiable presentation.
pub async fn sign_into_enveloped(
Expand All @@ -37,7 +45,7 @@ impl<T: Serialize> JoseVp<T> {
let jws = JWSPayload::sign(self, signer).await?;
Ok(EnvelopedVerifiablePresentation {
context: Context::iri_ref(ssi_vc::v2::CREDENTIALS_V2_CONTEXT_IRI.to_owned().into()),
id: format!("data:application/vp-ld+jwt;{jws}").parse().unwrap(),
id: format!("data:application/vp-ld+jwt,{jws}").parse().unwrap(),
})
}
}
Expand Down Expand Up @@ -88,3 +96,48 @@ impl<T: Presentation> Presentation for JoseVp<T> {
self.0.holders()
}
}

impl<E, P, T: ValidateClaims<E, P>> ValidateClaims<E, P> for JoseVp<T> {
fn validate_claims(&self, environment: &E, proof: &P) -> ClaimsValidity {
self.0.validate_claims(environment, proof)
}
}

#[cfg(test)]
mod tests {
use serde_json::json;
use ssi_claims_core::VerificationParameters;
use ssi_jwk::JWK;
use ssi_jws::{CompactJWS, CompactJWSBuf};
use ssi_vc::{enveloped::EnvelopedVerifiableCredential, v2::syntax::JsonPresentation};

use crate::JoseVp;

async fn verify(input: &CompactJWS, key: &JWK) {
let vp = JoseVp::decode_any(input).unwrap();
let params = VerificationParameters::from_resolver(key);
let result = vp.verify(params).await.unwrap();
assert_eq!(result, Ok(()))
}

#[async_std::test]
async fn jose_vp_roundtrip() {
let vp: JsonPresentation<EnvelopedVerifiableCredential> = serde_json::from_value(json!({
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://www.w3.org/ns/credentials/examples/v2"
],
"type": "VerifiablePresentation",
"verifiableCredential": [{
"@context": ["https://www.w3.org/ns/credentials/v2"],
"type": ["EnvelopedVerifiableCredential"],
"id": "data:application/vc-ld+jwt,eyJraWQiOiJFeEhrQk1XOWZtYmt2VjI2Nm1ScHVQMnNVWV9OX0VXSU4xbGFwVXpPOHJvIiwiYWxnIjoiRVMzODQifQ.eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvbnMvY3JlZGVudGlhbHMvdjIiLCJodHRwczovL3d3dy53My5vcmcvbnMvY3JlZGVudGlhbHMvZXhhbXBsZXMvdjIiXSwiaWQiOiJodHRwOi8vdW5pdmVyc2l0eS5leGFtcGxlL2NyZWRlbnRpYWxzLzE4NzIiLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiRXhhbXBsZUFsdW1uaUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiaHR0cHM6Ly91bml2ZXJzaXR5LmV4YW1wbGUvaXNzdWVycy81NjUwNDkiLCJ2YWxpZEZyb20iOiIyMDEwLTAxLTAxVDE5OjIzOjI0WiIsImNyZWRlbnRpYWxTY2hlbWEiOnsiaWQiOiJodHRwczovL2V4YW1wbGUub3JnL2V4YW1wbGVzL2RlZ3JlZS5qc29uIiwidHlwZSI6Ikpzb25TY2hlbWEifSwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZXhhbXBsZToxMjMiLCJkZWdyZWUiOnsidHlwZSI6IkJhY2hlbG9yRGVncmVlIiwibmFtZSI6IkJhY2hlbG9yIG9mIFNjaWVuY2UgYW5kIEFydHMifX19.d2k4O3FytQJf83kLh-HsXuPvh6yeOlhJELVo5TF71gu7elslQyOf2ZItAXrtbXF4Kz9WivNdztOayz4VUQ0Mwa8yCDZkP9B2pH-9S_tcAFxeoeJ6Z4XnFuL_DOfkR1fP"
}]
})).unwrap();

let key = JWK::generate_p256();
let enveloped = JoseVp(vp).sign_into_enveloped(&key).await.unwrap();
let jws = CompactJWSBuf::new(enveloped.id.decoded_data().unwrap().into_owned()).unwrap();
verify(&jws, &key).await
}
}

0 comments on commit 94ef9c2

Please sign in to comment.