diff --git a/Cargo.toml b/Cargo.toml index e958044495..6a6fb06ba6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,8 +23,8 @@ serde = { version = "1.0", default-features = false, features = ["alloc", "deriv thiserror = { version = "1.0", default-features = false } strum = { version = "0.25", default-features = false, features = ["std", "derive"] } serde_json = { version = "1.0", default-features = false } -json-proof-token = { version = "0.3.4" } -zkryptium = { version = "0.2.0", default-features = false, features = ["bbsplus"] } +json-proof-token = { version = "0.3.5" } +zkryptium = { version = "0.2.1", default-features = false, features = ["bbsplus"] } [workspace.package] authors = ["IOTA Stiftung"] diff --git a/examples/1_advanced/10_zkp_revocation.rs b/examples/1_advanced/10_zkp_revocation.rs index 6941f51a16..db30d71d71 100644 --- a/examples/1_advanced/10_zkp_revocation.rs +++ b/examples/1_advanced/10_zkp_revocation.rs @@ -151,7 +151,7 @@ async fn main() -> anyhow::Result<()> { &client, &secret_manager_issuer, &storage_issuer, - JwkMemStore::BLS12381SHA256_KEY_TYPE, + JwkMemStore::BLS12381G2_KEY_TYPE, None, Some(ProofAlgorithm::BLS12381_SHA256), ) diff --git a/examples/1_advanced/9_zkp.rs b/examples/1_advanced/9_zkp.rs index bca63edd94..744395c3cc 100644 --- a/examples/1_advanced/9_zkp.rs +++ b/examples/1_advanced/9_zkp.rs @@ -99,7 +99,7 @@ async fn main() -> anyhow::Result<()> { &client, &secret_manager_issuer, &storage_issuer, - JwkMemStore::BLS12381SHA256_KEY_TYPE, + JwkMemStore::BLS12381G2_KEY_TYPE, ProofAlgorithm::BLS12381_SHA256, ) .await?; diff --git a/identity_credential/src/presentation/jwp_presentation_builder.rs b/identity_credential/src/presentation/jwp_presentation_builder.rs index cb78123578..c1ad0c45a4 100644 --- a/identity_credential/src/presentation/jwp_presentation_builder.rs +++ b/identity_credential/src/presentation/jwp_presentation_builder.rs @@ -85,7 +85,7 @@ impl SelectiveDisclosurePresentation { /// Set Presentation Protected Header. pub fn set_presentation_header(&mut self, ph: PresentationProtectedHeader) { - self.jwp_builder.presentation_protected_header(ph); + self.jwp_builder.set_presentation_protected_header(ph); } /// Get the builder. diff --git a/identity_jose/src/jwk/curve/bls.rs b/identity_jose/src/jwk/curve/bls.rs index a93e48b3e3..aa241bee21 100644 --- a/identity_jose/src/jwk/curve/bls.rs +++ b/identity_jose/src/jwk/curve/bls.rs @@ -7,13 +7,17 @@ use core::fmt::Result; /// [More Info](https://datatracker.ietf.org/doc/html/draft-ietf-cose-bls-key-representations-05#name-curve-parameter-registratio) #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] pub enum BlsCurve { - /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 12 with 381-bit p in the subgroup of G1. + /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 12 with 381-bit p in the + /// subgroup of G1. BLS12381G1, - /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 12 with 381-bit p in the subgroup of G2. + /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 12 with 381-bit p in the + /// subgroup of G2. BLS12381G2, - /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 48 with 581-bit p in the subgroup of G1. + /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 48 with 581-bit p in the + /// subgroup of G1. BLS48581G1, - /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 48 with 581-bit p in the subgroup of G2. + /// A cryptographic key on the Barreto-Lynn-Scott (BLS) curve featuring an embedding degree 48 with 581-bit p in the + /// subgroup of G2. BLS48581G2, } @@ -33,4 +37,4 @@ impl Display for BlsCurve { fn fmt(&self, f: &mut Formatter<'_>) -> Result { f.write_str(self.name()) } -} \ No newline at end of file +} diff --git a/identity_jose/src/jwk/curve/mod.rs b/identity_jose/src/jwk/curve/mod.rs index d333ad879c..8e1627219f 100644 --- a/identity_jose/src/jwk/curve/mod.rs +++ b/identity_jose/src/jwk/curve/mod.rs @@ -1,12 +1,12 @@ // Copyright 2020-2023 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +mod bls; mod ec; mod ecx; mod ed; -mod bls; +pub use self::bls::*; pub use self::ec::*; pub use self::ecx::*; pub use self::ed::*; -pub use self::bls::*; \ No newline at end of file diff --git a/identity_jose/src/jwk/jwk_ext.rs b/identity_jose/src/jwk/jwk_ext.rs index 4b2c3b72fe..97f1d8a6f1 100644 --- a/identity_jose/src/jwk/jwk_ext.rs +++ b/identity_jose/src/jwk/jwk_ext.rs @@ -106,7 +106,7 @@ impl TryFrom for Jwk { let (kty, params) = match value.key_params { JwkAlgorithmParameters::EllipticCurve(p) => (JwkType::Ec, JwkParams::Ec(JwkParamsEc::from(p))), - _ => unreachable!() + _ => unreachable!(), }; Ok(Self { @@ -156,4 +156,4 @@ impl TryInto for &Jwk { key_params: params, }) } -} \ No newline at end of file +} diff --git a/identity_jose/src/jwk/key_params.rs b/identity_jose/src/jwk/key_params.rs index f60d6d5e66..ba3ca23059 100644 --- a/identity_jose/src/jwk/key_params.rs +++ b/identity_jose/src/jwk/key_params.rs @@ -10,6 +10,8 @@ use crate::jwk::EcxCurve; use crate::jwk::EdCurve; use crate::jwk::JwkType; +use super::BlsCurve; + /// Algorithm-specific parameters for JSON Web Keys. /// /// [More Info](https://tools.ietf.org/html/rfc7518#section-6) @@ -149,6 +151,17 @@ impl JwkParamsEc { _ => Err(Error::KeyError("Ec Curve")), } } + + /// Returns the [`BlsCurve`] if it is of a supported type. + pub fn try_bls_curve(&self) -> Result { + match &*self.crv { + "BLS12381G1" => Ok(BlsCurve::BLS12381G1), + "BLS12381G2" => Ok(BlsCurve::BLS12381G2), + "BLS48581G1" => Ok(BlsCurve::BLS48581G1), + "BLS48581G2" => Ok(BlsCurve::BLS48581G2), + _ => Err(Error::KeyError("BLS Curve")), + } + } } impl From for JwkParams { diff --git a/identity_storage/src/key_storage/bls.rs b/identity_storage/src/key_storage/bls.rs new file mode 100644 index 0000000000..11d27f475d --- /dev/null +++ b/identity_storage/src/key_storage/bls.rs @@ -0,0 +1,87 @@ +use identity_verification::jose::jwk::Jwk; +use identity_verification::jose::jwu; +use identity_verification::jwk::BlsCurve; +use identity_verification::jwk::JwkParamsEc; +use zkryptium::bbsplus::keys::BBSplusPublicKey; +use zkryptium::bbsplus::keys::BBSplusSecretKey; + +use crate::key_storage::KeyStorageError; +use crate::key_storage::KeyStorageErrorKind; +use crate::key_storage::KeyStorageResult; + +pub(crate) fn expand_bls_jwk(jwk: &Jwk) -> KeyStorageResult<(BBSplusSecretKey, BBSplusPublicKey)> { + let params: &JwkParamsEc = jwk.try_ec_params().unwrap(); + + if params + .try_bls_curve() + .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType).with_source(err))? + != BlsCurve::BLS12381G2 + { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("expected an {} key", BlsCurve::BLS12381G2.name())), + ); + } + + let sk: BBSplusSecretKey = params + .d + .as_deref() + .map(jwu::decode_b64) + .ok_or_else(|| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("expected Jwk `d` param to be present") + })? + .map(|v| BBSplusSecretKey::from_bytes(&v)) + .map_err(|err| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message("unable to decode `d` param") + .with_source(err) + })? + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!("invalid BBS+ secret key")) + })?; + + let x: [u8; BBSplusPublicKey::COORDINATE_LEN] = jwu::decode_b64(¶ms.x) + .map_err(|err| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message("unable to decode `x` param") + .with_source(err) + })? + .try_into() + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message(format!("expected key of length {}", BBSplusPublicKey::COORDINATE_LEN)) + })?; + + let y: [u8; BBSplusPublicKey::COORDINATE_LEN] = jwu::decode_b64(¶ms.y) + .map_err(|err| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message("unable to decode `y` param") + .with_source(err) + })? + .try_into() + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified) + .with_custom_message(format!("expected key of length {}", BBSplusPublicKey::COORDINATE_LEN)) + })?; + + let pk = BBSplusPublicKey::from_coordinates(&x, &y).map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!("invalid BBS+ public key")) + })?; + + Ok((sk, pk)) +} + +#[cfg(any(test, feature = "memstore"))] +pub(crate) fn encode_bls_jwk(private_key: &BBSplusSecretKey, public_key: &BBSplusPublicKey) -> Jwk { + let (x, y) = public_key.to_coordinates(); + let x = jwu::encode_b64(x); + let y = jwu::encode_b64(y); + + let d = jwu::encode_b64(private_key.to_bytes()); + let mut params = JwkParamsEc::new(); + params.x = x; + params.y = y; + params.d = Some(d); + params.crv = BlsCurve::BLS12381G2.name().to_owned(); + Jwk::from_params(params) +} diff --git a/identity_storage/src/key_storage/jwk_storage.rs b/identity_storage/src/key_storage/jwk_storage.rs index d74f51b077..1e0fa4055a 100644 --- a/identity_storage/src/key_storage/jwk_storage.rs +++ b/identity_storage/src/key_storage/jwk_storage.rs @@ -9,8 +9,6 @@ use async_trait::async_trait; use identity_verification::jose::jwk::Jwk; use identity_verification::jose::jws::JwsAlgorithm; use jsonprooftoken::jpa::algs::ProofAlgorithm; -use jsonprooftoken::jpt::claims::JptClaims; -use jsonprooftoken::jwp::header::IssuerProtectedHeader; use zkryptium::bbsplus::signature::BBSplusSignature; use super::jwk_gen_output::JwkGenOutput; @@ -73,23 +71,24 @@ pub trait JwkStorage: storage_sub_trait::StorageSendSyncMaybe { #[cfg_attr(feature = "send-sync-storage", async_trait)] pub trait JwkStorageExt: JwkStorage { /// Generates a JWK representing a BBS+ signature - async fn generate_bbs_key(&self, key_type: KeyType, alg: ProofAlgorithm) -> KeyStorageResult; + async fn generate_bbs(&self, key_type: KeyType, alg: ProofAlgorithm) -> KeyStorageResult; - /// Generate the JPT representing a JWP in the Issuer form - async fn generate_issuer_proof( + /// Sign the provided `data` and `header` using the private key identified by `key_id` according to the requirements + /// of the corresponding `public_key` (see [`Jwk::alg`](Jwk::alg()) etc.). + async fn sign_bbs( &self, key_id: &KeyId, - header: IssuerProtectedHeader, - claims: JptClaims, + data: &[Vec], + header: &[u8], public_key: &Jwk, - ) -> KeyStorageResult; + ) -> KeyStorageResult>; /// Update proof functionality for timeframe revocation mechanism - async fn update_proof( + async fn update_signature( &self, key_id: &KeyId, public_key: &Jwk, - proof: &[u8; BBSplusSignature::BYTES], + signature: &[u8; BBSplusSignature::BYTES], ctx: ProofUpdateCtx, ) -> KeyStorageResult<[u8; BBSplusSignature::BYTES]>; } diff --git a/identity_storage/src/key_storage/memstore.rs b/identity_storage/src/key_storage/memstore.rs index b0a8061666..d264144a9a 100644 --- a/identity_storage/src/key_storage/memstore.rs +++ b/identity_storage/src/key_storage/memstore.rs @@ -14,23 +14,20 @@ use identity_verification::jose::jwk::JwkType; use identity_verification::jose::jws::JwsAlgorithm; use identity_verification::jwk::BlsCurve; use identity_verification::jwu; -use jsonprooftoken::encoding::SerializationType; use jsonprooftoken::jpa::algs::ProofAlgorithm; -use jsonprooftoken::jpt::claims::JptClaims; -use jsonprooftoken::jwk::key::Jwk as JwkExt; -use jsonprooftoken::jwk::types::KeyPairSubtype; -use jsonprooftoken::jwp::header::IssuerProtectedHeader; -use jsonprooftoken::jwp::issued::JwpIssuedBuilder; use rand::distributions::DistString; use shared::Shared; use tokio::sync::RwLockReadGuard; use tokio::sync::RwLockWriteGuard; use zkryptium::bbsplus::keys::BBSplusSecretKey; use zkryptium::bbsplus::signature::BBSplusSignature; +use zkryptium::keys::pair::KeyPair; use zkryptium::schemes::algorithms::BbsBls12381Sha256; use zkryptium::schemes::algorithms::BbsBls12381Shake256; use zkryptium::schemes::generics::Signature; +use super::bls::encode_bls_jwk; +use super::bls::expand_bls_jwk; use super::ed25519::encode_jwk; use super::ed25519::expand_secret_jwk; use super::jwk_gen_output::JwkGenOutput; @@ -82,6 +79,12 @@ impl JwkStorage for JwkMemStore { let public_key = private_key.public_key(); (private_key, public_key) } + other => { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("{other} is not supported")), + ); + } }; let kid: KeyId = random_key_id(); @@ -199,6 +202,7 @@ impl JwkStorage for JwkMemStore { #[derive(Debug, Copy, Clone)] enum MemStoreKeyType { Ed25519, + BLS12381G2, } impl JwkMemStore { @@ -206,19 +210,16 @@ impl JwkMemStore { /// The Ed25519 key type. pub const ED25519_KEY_TYPE: KeyType = KeyType::from_static_str(Self::ED25519_KEY_TYPE_STR); - const BLS12381SHA256_KEY_TYPE_STR: &'static str = "Bls12381Sha256"; - /// The BLS12381-SHA256 key type - pub const BLS12381SHA256_KEY_TYPE: KeyType = KeyType::from_static_str(Self::BLS12381SHA256_KEY_TYPE_STR); - - const BLS12381SHAKE256_KEY_TYPE_STR: &'static str = "Bls12381Shake256"; - /// The BLS12381-SHAKE256 key type - pub const BLS12381SHAKE256_KEY_TYPE: KeyType = KeyType::from_static_str(Self::BLS12381SHAKE256_KEY_TYPE_STR); + const BLS12381G2_KEY_TYPE_STR: &'static str = "BLS12381G2"; + /// The BLS12381G2 key type + pub const BLS12381G2_KEY_TYPE: KeyType = KeyType::from_static_str(Self::BLS12381G2_KEY_TYPE_STR); } impl MemStoreKeyType { const fn name(&self) -> &'static str { match self { MemStoreKeyType::Ed25519 => "Ed25519", + MemStoreKeyType::BLS12381G2 => "BLS12381G2", } } } @@ -235,6 +236,7 @@ impl TryFrom<&KeyType> for MemStoreKeyType { fn try_from(value: &KeyType) -> Result { match value.as_str() { JwkMemStore::ED25519_KEY_TYPE_STR => Ok(MemStoreKeyType::Ed25519), + JwkMemStore::BLS12381G2_KEY_TYPE_STR => Ok(MemStoreKeyType::BLS12381G2), _ => Err(KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType)), } } @@ -263,6 +265,24 @@ impl TryFrom<&Jwk> for MemStoreKeyType { ), } } + JwkType::Ec => { + let ec_params = jwk.try_ec_params().map_err(|err| { + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message("expected EC parameters for a JWK with `kty` Ec") + .with_source(err) + })?; + match ec_params.try_bls_curve().map_err(|err| { + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message("only Ed curves are supported for signing") + .with_source(err) + })? { + BlsCurve::BLS12381G2 => Ok(MemStoreKeyType::BLS12381G2), + curve => Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("{curve} not supported")), + ), + } + } other => Err( KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) .with_custom_message(format!("Jwk `kty` {other} not supported")), @@ -293,22 +313,61 @@ fn check_key_alg_compatibility(key_type: MemStoreKeyType, alg: JwsAlgorithm) -> } } +/// Check that the key type can be used with the algorithm. +fn check_key_proof_alg_compatibility(key_type: MemStoreKeyType, alg: ProofAlgorithm) -> KeyStorageResult<()> { + match (key_type, alg) { + (MemStoreKeyType::BLS12381G2, ProofAlgorithm::BLS12381_SHA256) => Ok(()), + (MemStoreKeyType::BLS12381G2, ProofAlgorithm::BLS12381_SHAKE256) => Ok(()), + (key_type, alg) => Err( + KeyStorageError::new(crate::key_storage::KeyStorageErrorKind::KeyAlgorithmMismatch) + .with_custom_message(format!("`cannot use key type `{key_type}` with algorithm `{alg}`")), + ), + } +} + /// JwkStorageExt implementation for JwkMemStore #[cfg_attr(not(feature = "send-sync-storage"), async_trait(?Send))] #[cfg_attr(feature = "send-sync-storage", async_trait)] impl JwkStorageExt for JwkMemStore { - async fn generate_bbs_key(&self, key_type: KeyType, alg: ProofAlgorithm) -> KeyStorageResult { - let keysubtype = - KeyPairSubtype::from_str(key_type.as_str()).map_err(|_| KeyStorageErrorKind::UnsupportedKeyType)?; + async fn generate_bbs(&self, key_type: KeyType, alg: ProofAlgorithm) -> KeyStorageResult { + let key_type: MemStoreKeyType = MemStoreKeyType::try_from(&key_type)?; - let mut jwk = Jwk::try_from( - JwkExt::generate(keysubtype) - .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::RetryableIOFailure).with_source(err))?, - ) - .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::RetryableIOFailure).with_source(err))?; + check_key_proof_alg_compatibility(key_type, alg)?; + + let (private_key, public_key) = match key_type { + MemStoreKeyType::BLS12381G2 => match alg { + ProofAlgorithm::BLS12381_SHA256 => { + let keypair = KeyPair::::random() + .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_source(err))?; + let sk = keypair.private_key().clone(); + let pk = keypair.public_key().clone(); + (sk, pk) + } + ProofAlgorithm::BLS12381_SHAKE256 => { + let keypair = KeyPair::::random() + .map_err(|err| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_source(err))?; + let sk = keypair.private_key().clone(); + let pk = keypair.public_key().clone(); + (sk, pk) + } + other => { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("{other} is not supported")), + ); + } + }, + other => { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedKeyType) + .with_custom_message(format!("{other} is not supported")), + ); + } + }; let kid: KeyId = random_key_id(); + let mut jwk: Jwk = encode_bls_jwk(&private_key, &public_key); jwk.set_alg(alg.to_string()); jwk.set_kid(jwk.thumbprint_sha256_b64()); let public_jwk: Jwk = jwk.to_public().expect("should only panic if kty == oct"); @@ -319,13 +378,13 @@ impl JwkStorageExt for JwkMemStore { Ok(JwkGenOutput::new(kid, public_jwk)) } - async fn generate_issuer_proof( + async fn sign_bbs( &self, key_id: &KeyId, - header: IssuerProtectedHeader, - claims: JptClaims, + data: &[Vec], + header: &[u8], public_key: &Jwk, - ) -> KeyStorageResult { + ) -> KeyStorageResult> { let jwk_store: RwLockReadGuard<'_, JwkKeyStore> = self.jwk_store.read().await; // Extract the required alg from the given public key @@ -365,25 +424,34 @@ impl JwkStorageExt for JwkMemStore { .get(key_id) .ok_or_else(|| KeyStorageError::new(KeyStorageErrorKind::KeyNotFound))?; - // Deserialize JSON to JwkExt - let jwk_ext: JwkExt = jwk.try_into().map_err(|_| KeyStorageErrorKind::SerializationError)?; + let (sk, pk) = expand_bls_jwk(jwk)?; - let jwp = JwpIssuedBuilder::new() - .issuer_protected_header(header) - .jpt_claims(claims) - .build(&jwk_ext) - .map_err(|_| KeyStorageErrorKind::Unspecified)? - .encode(SerializationType::COMPACT) - .map_err(|_| KeyStorageErrorKind::Unspecified)?; + let signature = match alg { + ProofAlgorithm::BLS12381_SHA256 => { + Signature::::sign(Some(data), &sk, &pk, Some(header)).map(|s| s.to_bytes()) + } + ProofAlgorithm::BLS12381_SHAKE256 => { + Signature::::sign(Some(data), &sk, &pk, Some(header)).map(|s| s.to_bytes()) + } + other => { + return Err( + KeyStorageError::new(KeyStorageErrorKind::UnsupportedProofAlgorithm) + .with_custom_message(format!("{other} is not supported")), + ); + } + } + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message(format!("signature failed")) + })?; - Ok(jwp) + Ok(signature.to_vec()) } - async fn update_proof( + async fn update_signature( &self, key_id: &KeyId, public_key: &Jwk, - proof: &[u8; BBSplusSignature::BYTES], + signature: &[u8; BBSplusSignature::BYTES], ctx: ProofUpdateCtx, ) -> KeyStorageResult<[u8; BBSplusSignature::BYTES]> { let jwk_store: RwLockReadGuard<'_, JwkKeyStore> = self.jwk_store.read().await; @@ -451,65 +519,67 @@ impl JwkStorageExt for JwkMemStore { .with_custom_message("unable to decode `d` param") .with_source(err) })?, - ).map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message("key not valid") - })?; + ) + .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("key not valid"))?; let new_proof = match alg { ProofAlgorithm::BLS12381_SHA256 => { - let proof = Signature::::from_bytes(proof) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature not valid"))? - .update_signature( - &sk, - &old_start_validity_timeframe, - &new_start_validity_timeframe, - index_start_validity_timeframe, - number_of_signed_messages, - ).map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message("Signature update failed") - })?; - - proof - .update_signature( - &sk, - &old_end_validity_timeframe, - &new_end_validity_timeframe, - index_end_validity_timeframe, - number_of_signed_messages, - ).map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message("Signature update failed") - })? - .to_bytes() + let signature = Signature::::from_bytes(signature) + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature not valid") + })? + .update_signature( + &sk, + &old_start_validity_timeframe, + &new_start_validity_timeframe, + index_start_validity_timeframe, + number_of_signed_messages, + ) + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature update failed") + })?; + + signature + .update_signature( + &sk, + &old_end_validity_timeframe, + &new_end_validity_timeframe, + index_end_validity_timeframe, + number_of_signed_messages, + ) + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature update failed") + })? + .to_bytes() } ProofAlgorithm::BLS12381_SHAKE256 => { - let proof = Signature::::from_bytes(proof) - .map_err(|_| KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature not valid"))? - .update_signature( - &sk, - &old_start_validity_timeframe, - &new_start_validity_timeframe, - index_start_validity_timeframe, - number_of_signed_messages, - ).map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message("Signature update failed") - })?; + let proof = Signature::::from_bytes(signature) + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature not valid") + })? + .update_signature( + &sk, + &old_start_validity_timeframe, + &new_start_validity_timeframe, + index_start_validity_timeframe, + number_of_signed_messages, + ) + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature update failed") + })?; proof - .update_signature( - &sk, - &old_end_validity_timeframe, - &new_end_validity_timeframe, - index_end_validity_timeframe, - number_of_signed_messages, - ).map_err(|_| { - KeyStorageError::new(KeyStorageErrorKind::Unspecified) - .with_custom_message("Signature update failed") - })? - .to_bytes() + .update_signature( + &sk, + &old_end_validity_timeframe, + &new_end_validity_timeframe, + index_end_validity_timeframe, + number_of_signed_messages, + ) + .map_err(|_| { + KeyStorageError::new(KeyStorageErrorKind::Unspecified).with_custom_message("Signature update failed") + })? + .to_bytes() } other => { return Err( diff --git a/identity_storage/src/key_storage/mod.rs b/identity_storage/src/key_storage/mod.rs index 70006b0537..5daf049bbc 100644 --- a/identity_storage/src/key_storage/mod.rs +++ b/identity_storage/src/key_storage/mod.rs @@ -6,6 +6,8 @@ //! This module provides the [`JwkStorage`] trait that //! abstracts over storages that store JSON Web Keys. +#[cfg(feature = "memstore")] +mod bls; #[cfg(feature = "memstore")] mod ed25519; mod jwk_gen_output; diff --git a/identity_storage/src/storage/jwp_document_ext.rs b/identity_storage/src/storage/jwp_document_ext.rs index b99f2f23a2..5da1608af5 100644 --- a/identity_storage/src/storage/jwp_document_ext.rs +++ b/identity_storage/src/storage/jwp_document_ext.rs @@ -9,6 +9,7 @@ use crate::Storage; use crate::StorageResult; use async_trait::async_trait; use identity_core::common::Object; +use identity_core::convert::ToJson; use identity_credential::credential::Credential; use identity_credential::credential::Jpt; use identity_credential::credential::JwpCredentialOptions; @@ -25,6 +26,7 @@ use jsonprooftoken::jpt::claims::JptClaims; use jsonprooftoken::jwk::key::Jwk; use jsonprooftoken::jwp::header::IssuerProtectedHeader; use jsonprooftoken::jwp::header::PresentationProtectedHeader; +use jsonprooftoken::jwp::issued::JwpIssuedBuilder; use serde::de::DeserializeOwned; use serde::Serialize; @@ -99,7 +101,7 @@ generate_method_for_document_type!( CoreDocument, ProofAlgorithm, JwkStorageExt, - JwkStorageExt::generate_bbs_key, + JwkStorageExt::generate_bbs, generate_method_core_document ); @@ -163,17 +165,27 @@ impl JwpDocumentExt for CoreDocument { .await .map_err(Error::KeyIdStorageError)?; - let jwp = ::generate_issuer_proof( - storage.key_storage(), - &key_id, - issuer_header, - jpt_claims.clone(), - jwk, - ) - .await - .map_err(Error::KeyStorageError)?; + let jwp_builder = JwpIssuedBuilder::new(issuer_header, jpt_claims.clone()); + + let header = jwp_builder.get_issuer_protected_header().map_or_else( + || Err(Error::JwpBuildingError), + |h| h.to_json_vec().map_err(|_| Error::JwpBuildingError), + )?; + + let data = jwp_builder.get_payloads().map_or_else( + || Err(Error::JwpBuildingError), + |p| p.to_bytes().map_err(|_| Error::JwpBuildingError), + )?; + + let signature = ::sign_bbs(storage.key_storage(), &key_id, &data, &header, jwk) + .await + .map_err(Error::KeyStorageError)?; - Ok(jwp) + jwp_builder + .build_with_proof(signature) + .map_err(|_| Error::JwpBuildingError)? + .encode(SerializationType::COMPACT) + .map_err(|err| Error::EncodingError(Box::new(err))) } async fn create_presented_jwp( @@ -262,7 +274,7 @@ mod iota_document { IotaDocument, ProofAlgorithm, JwkStorageExt, - JwkStorageExt::generate_bbs_key, + JwkStorageExt::generate_bbs, generate_method_iota_document ); diff --git a/identity_storage/src/storage/timeframe_revocation_ext.rs b/identity_storage/src/storage/timeframe_revocation_ext.rs index d03b7d5d8d..766eff7acc 100644 --- a/identity_storage/src/storage/timeframe_revocation_ext.rs +++ b/identity_storage/src/storage/timeframe_revocation_ext.rs @@ -147,9 +147,10 @@ impl TimeframeRevocationExtension for CoreDocument { number_of_signed_messages: payloads.0.len(), }; - let new_proof = ::update_proof(storage.key_storage(), &key_id, jwk, &proof, proof_update_ctx) - .await - .map_err(Error::KeyStorageError)?; + let new_proof = + ::update_signature(storage.key_storage(), &key_id, jwk, &proof, proof_update_ctx) + .await + .map_err(Error::KeyStorageError)?; credential_jwp.set_proof(&new_proof); credential_jwp.set_payloads(payloads);