diff --git a/did-ethr/src/lib.rs b/did-ethr/src/lib.rs index 80773da73..686b92c1f 100644 --- a/did-ethr/src/lib.rs +++ b/did-ethr/src/lib.rs @@ -324,6 +324,7 @@ mod tests { use serde_json::json; use ssi_dids::did_resolve::ResolutionInputMetadata; use ssi_jwk::JWK; + use ssi_ldp::{ProofSuite, ProofSuiteType}; #[test] fn jwk_to_did_ethr() { @@ -471,8 +472,7 @@ mod tests { // Check that proof JWK must match proof verificationMethod let mut vc_wrong_key = vc_no_proof.clone(); let other_key = JWK::generate_ed25519().unwrap(); - use ssi_ldp::ProofSuite; - let proof_bad = ssi_ldp::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 + let proof_bad = ProofSuiteType::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 .sign( &vc_no_proof, &issue_options, diff --git a/did-ion/src/lib.rs b/did-ion/src/lib.rs index 0a6aba7e2..fed2b331e 100644 --- a/did-ion/src/lib.rs +++ b/did-ion/src/lib.rs @@ -7,6 +7,7 @@ use sidetree::{is_secp256k1, Sidetree, SidetreeClient, SidetreeError}; pub const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); +#[derive(Clone)] pub struct ION; /// did:ion Method diff --git a/did-ion/src/sidetree.rs b/did-ion/src/sidetree.rs index 4264a62c0..6dfbb0b93 100644 --- a/did-ion/src/sidetree.rs +++ b/did-ion/src/sidetree.rs @@ -1404,6 +1404,7 @@ impl HTTPSidetreeDIDResolver { } /// Sidetree DID Method client implementation +#[derive(Clone)] pub struct SidetreeClient { pub resolver: Option>, pub endpoint: Option, diff --git a/did-onion/src/lib.rs b/did-onion/src/lib.rs index 87648f9e9..3951fb397 100644 --- a/did-onion/src/lib.rs +++ b/did-onion/src/lib.rs @@ -14,6 +14,7 @@ const TOR_SOCKS_PORT: usize = 9050; /// /// [Specification](https://blockchaincommons.github.io/did-method-onion/) #[non_exhaustive] +#[derive(Clone)] pub struct DIDOnion { pub proxy_url: String, } diff --git a/did-pkh/src/lib.rs b/did-pkh/src/lib.rs index 8d4eba803..5cc3d1371 100644 --- a/did-pkh/src/lib.rs +++ b/did-pkh/src/lib.rs @@ -679,7 +679,7 @@ mod tests { use serde_json::{from_str, from_value, json}; use ssi_core::one_or_many::OneOrMany; use ssi_jwk::Algorithm; - use ssi_ldp::{Proof, ProofSuite}; + use ssi_ldp::{Proof, ProofSuite, ProofSuiteType}; fn test_generate(jwk_value: Value, type_: &str, did_expected: &str) { let jwk: JWK = from_value(jwk_value).unwrap(); @@ -1101,7 +1101,7 @@ mod tests { eprintln!("sig: {}", sig); // Complete issuance - let proof = proof_suite.complete(prep, &sig).await.unwrap(); + let proof = proof_suite.complete(&prep, &sig).await.unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); @@ -1178,7 +1178,7 @@ mod tests { .await .unwrap(); let sig = sign_tezos(&prep, algorithm, &key); - let vp_proof = proof_suite.complete(prep, &sig).await.unwrap(); + let vp_proof = proof_suite.complete(&prep, &sig).await.unwrap(); vp.add_proof(vp_proof); println!("VP: {}", serde_json::to_string_pretty(&vp).unwrap()); vp.validate().unwrap(); @@ -1250,7 +1250,7 @@ mod tests { other_key_secp256k1.clone(), "eip155", "#blockchainAccountId", - &ssi_ldp::EcdsaSecp256k1RecoverySignature2020, + &ProofSuiteType::EcdsaSecp256k1RecoverySignature2020, None, None, ) @@ -1262,7 +1262,7 @@ mod tests { other_key_secp256k1.clone(), "eip155", "#blockchainAccountId", - &ssi_ldp::Eip712Signature2021, + &ProofSuiteType::Eip712Signature2021, None, None, ) @@ -1274,7 +1274,7 @@ mod tests { other_key_secp256k1.clone(), "eip155", "#blockchainAccountId", - &ssi_ldp::EthereumPersonalSignature2021, + &ProofSuiteType::EthereumPersonalSignature2021, None, None, ) @@ -1370,7 +1370,7 @@ mod tests { other_key_secp256k1.clone(), "eip155", "#blockchainAccountId", - &ssi_ldp::EthereumEip712Signature2021, + &ProofSuiteType::EthereumEip712Signature2021, Some(eip712_domain), Some(vp_eip712_domain), ) @@ -1382,7 +1382,7 @@ mod tests { other_key_secp256k1.clone(), "eip155", "#blockchainAccountId", - &ssi_ldp::Eip712Signature2021, + &ProofSuiteType::Eip712Signature2021, None, None, ) @@ -1396,7 +1396,7 @@ mod tests { other_key_ed25519.clone(), "tz", "#blockchainAccountId", - &ssi_ldp::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021, + &ProofSuiteType::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021, None, None, ) @@ -1423,7 +1423,7 @@ mod tests { other_key_p256.clone(), "tz", "#blockchainAccountId", - &ssi_ldp::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021, + &ProofSuiteType::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021, None, None, ) @@ -1437,7 +1437,7 @@ mod tests { other_key_ed25519.clone(), "sol", "#controller", - &ssi_ldp::Ed25519Signature2018, + &ProofSuiteType::Ed25519Signature2018, None, None, ) @@ -1461,7 +1461,7 @@ mod tests { other_key_secp256k1.clone(), "btc", "#blockchainAccountId", - &ssi_ldp::EcdsaSecp256k1RecoverySignature2020, + &ProofSuiteType::EcdsaSecp256k1RecoverySignature2020, None, None, ) @@ -1473,7 +1473,7 @@ mod tests { other_key_secp256k1.clone(), "doge", "#blockchainAccountId", - &ssi_ldp::EcdsaSecp256k1RecoverySignature2020, + &ProofSuiteType::EcdsaSecp256k1RecoverySignature2020, None, None, ) @@ -1488,7 +1488,7 @@ mod tests { other_key_ed25519.clone(), "tz", "#TezosMethod2021", - &ssi_ldp::TezosSignature2021, + &ProofSuiteType::TezosSignature2021, ) .await; key_ed25519.algorithm = Some(Algorithm::EdDSA); @@ -1516,7 +1516,7 @@ mod tests { other_key_p256.clone(), "tz", "#TezosMethod2021", - &ssi_ldp::TezosSignature2021, + &ProofSuiteType::TezosSignature2021, ) .await; key_p256.algorithm = Some(Algorithm::ES256); diff --git a/did-sol/src/lib.rs b/did-sol/src/lib.rs index 0a1650927..d527f1bf9 100644 --- a/did-sol/src/lib.rs +++ b/did-sol/src/lib.rs @@ -203,6 +203,7 @@ mod tests { use serde_json::json; use ssi_dids::did_resolve::ResolutionInputMetadata; use ssi_jwk::JWK; + use ssi_ldp::{ProofSuite, ProofSuiteType}; #[test] fn key_to_did_sol() { @@ -299,8 +300,7 @@ mod tests { // Check that proof JWK must match proof verificationMethod let mut vc_wrong_key = vc_no_proof.clone(); let other_key = JWK::generate_ed25519().unwrap(); - use ssi_ldp::ProofSuite; - let proof_bad = ssi_ldp::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 + let proof_bad = ProofSuiteType::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 .sign( &vc_no_proof, &issue_options, diff --git a/did-tezos/src/lib.rs b/did-tezos/src/lib.rs index 54a806b09..351681d29 100644 --- a/did-tezos/src/lib.rs +++ b/did-tezos/src/lib.rs @@ -25,7 +25,7 @@ mod explorer; /// did:tz DID Method /// /// [Specification](https://github.com/spruceid/did-tezos/) -#[derive(Default)] +#[derive(Default, Clone)] pub struct DIDTz { tzkt_url: Option, } @@ -563,6 +563,7 @@ mod tests { use ssi_dids::did_resolve::ResolutionInputMetadata; use ssi_dids::ServiceEndpoint; use ssi_jws::encode_sign; + use ssi_ldp::{ProofSuite, ProofSuiteType}; use std::collections::BTreeMap as Map; const TZ1: &str = "did:tz:tz1YwA1FwpgLtc1G8DKbbZ6e6PTb1dQMRn5x"; @@ -856,8 +857,7 @@ mod tests { // Check that proof JWK must match proof verificationMethod let mut vc_wrong_key = vc_no_proof.clone(); let other_key = JWK::generate_ed25519().unwrap(); - use ssi_ldp::ProofSuite; - let proof_bad = ssi_ldp::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 + let proof_bad = ProofSuiteType::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 .sign( &vc_no_proof, &issue_options, @@ -1052,8 +1052,7 @@ mod tests { // Check that proof JWK must match proof verificationMethod let mut vc_wrong_key = vc_no_proof.clone(); let other_key = JWK::generate_ed25519().unwrap(); - use ssi_ldp::ProofSuite; - let proof_bad = ssi_ldp::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 + let proof_bad = ProofSuiteType::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 .sign( &vc_no_proof, &issue_options, @@ -1520,8 +1519,7 @@ mod tests { // Check that proof JWK must match proof verificationMethod let mut vc_wrong_key = vc_no_proof.clone(); let other_key = JWK::generate_p256().unwrap(); - use ssi_ldp::ProofSuite; - let proof_bad = ssi_ldp::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 + let proof_bad = ProofSuiteType::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 .sign( &vc_no_proof, &issue_options, diff --git a/examples/zcap_invocation.jsonld b/examples/zcap_invocation.jsonld index bfeffb29f..1166d69a8 100644 --- a/examples/zcap_invocation.jsonld +++ b/examples/zcap_invocation.jsonld @@ -3,7 +3,7 @@ "id": "urn:uuid:ad86cb2c-e9db-434a-beae-71b82120a8a4", "capabilityAction": "Drive", "proof": { - "type": "RsaSignature2016", + "type": "Ed25519Signature2018", "proofPurpose": "capabilityInvocation", "capability": "https://whatacar.example/a-fancy-car/proc/7a397d7b", "created": "2016-02-08T17:13:48Z", diff --git a/src/lib.rs b/src/lib.rs index 19e3a5e40..0882fca86 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,38 +20,56 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg), feature(doc_cfg))] // maintain old structure here +pub use ssi_caips as caips; +#[deprecated = "Use ssi::caips::caip10"] pub use ssi_caips::caip10; +#[deprecated = "Use ssi::caips::caip2"] pub use ssi_caips::caip2; +pub use ssi_core as core; +#[deprecated = "Use ssi::core::one_or_many"] pub use ssi_core::one_or_many; +pub use ssi_crypto as crypto; +#[deprecated = "Use ssi::crypto::hashes"] pub use ssi_crypto::hashes as hash; #[cfg(feature = "eip")] +#[deprecated = "Use ssi::crypto::hashes::keccak"] pub use ssi_crypto::hashes::keccak; #[cfg(feature = "bbs")] +#[deprecated = "Use ssi::crypto::signatures::bbs"] pub use ssi_crypto::signatures::bbs; pub use ssi_dids as did; +#[deprecated = "Use ssi::did::did_resolve"] pub use ssi_dids::did_resolve; pub use ssi_json_ld as jsonld; +#[deprecated = "Use ssi::jsonld::rdf"] pub use ssi_json_ld::rdf; +#[deprecated = "Use ssi::jsonld::urdna2015"] pub use ssi_json_ld::urdna2015; pub use ssi_jwk as jwk; +#[cfg(feature = "aleo")] +#[deprecated = "Use ssi::jwk::aleo"] +pub use ssi_jwk::aleo; +#[deprecated = "Use ssi::jwk::blakesig"] pub use ssi_jwk::blakesig; +#[deprecated = "Use ssi::jwk::der"] pub use ssi_jwk::der; #[cfg(feature = "ripemd-160")] +#[deprecated = "Use ssi::jwk::ripemd160"] pub use ssi_jwk::ripemd160 as ripemd; pub use ssi_jws as jws; pub use ssi_jwt as jwt; pub use ssi_ldp as ldp; #[cfg(feature = "eip")] +#[deprecated = "Use ssi::ldp::eip712"] pub use ssi_ldp::eip712; +#[deprecated = "Use ssi::ldp::soltx"] pub use ssi_ldp::soltx; pub use ssi_ssh as ssh; pub use ssi_tzkey as tzkey; pub use ssi_ucan as ucan; pub use ssi_vc as vc; +#[deprecated = "Use ssi::vc::revocation"] +pub use ssi_vc::revocation; pub use ssi_zcap_ld as zcap; -pub use vc::revocation; - -#[cfg(feature = "aleo")] -pub use ssi_jwk::aleo; pub const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); diff --git a/ssi-dids/src/lib.rs b/ssi-dids/src/lib.rs index 3455867d9..5251c4c1c 100644 --- a/ssi-dids/src/lib.rs +++ b/ssi-dids/src/lib.rs @@ -590,7 +590,7 @@ pub enum DIDMethodError { /// Registries](https://www.w3.org/TR/did-spec-registries/#did-methods). #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] -pub trait DIDMethod: Sync { +pub trait DIDMethod: Sync + Send { /// Get the DID method's name. /// /// `method-name` in [DID Syntax](https://w3c.github.io/did-core/#did-syntax). diff --git a/ssi-jws/src/lib.rs b/ssi-jws/src/lib.rs index 1772e48d8..ffbc67e39 100644 --- a/ssi-jws/src/lib.rs +++ b/ssi-jws/src/lib.rs @@ -546,8 +546,8 @@ pub fn prepare_detached_unencoded_payload( Ok((header, signing_input)) } -pub fn complete_sign_unencoded_payload(header: Header, sig_b64: &str) -> Result { - let header_b64 = base64_encode_json(&header)?; +pub fn complete_sign_unencoded_payload(header: &Header, sig_b64: &str) -> Result { + let header_b64 = base64_encode_json(header)?; let jws = header_b64 + ".." + sig_b64; Ok(jws) } diff --git a/ssi-ldp/Cargo.toml b/ssi-ldp/Cargo.toml index 5d24c7fe8..27237f137 100644 --- a/ssi-ldp/Cargo.toml +++ b/ssi-ldp/Cargo.toml @@ -24,6 +24,7 @@ aleo = ["ssi-jws/aleo", "ssi-caips/aleo"] solana = [] example-http-issuer = [] +test = [] [dependencies] thiserror = "1.0" diff --git a/ssi-ldp/src/error.rs b/ssi-ldp/src/error.rs index 118a8efe3..e48ffd675 100644 --- a/ssi-ldp/src/error.rs +++ b/ssi-ldp/src/error.rs @@ -26,8 +26,8 @@ pub enum Error { UnsupportedNonDIDIssuer(String), #[error("Missing proof purpose")] MissingProofPurpose, - #[error("Linked Data Proof type not implemented")] - ProofTypeNotImplemented, + #[error("Linked Data Proof type not implemented or not enabled by feature")] + ProofTypeNotSupported, #[error("Unsupported curve")] UnsupportedCurve, #[error("Missing type")] diff --git a/ssi-ldp/src/lib.rs b/ssi-ldp/src/lib.rs index fd8d20bf1..d7c2eae08 100644 --- a/ssi-ldp/src/lib.rs +++ b/ssi-ldp/src/lib.rs @@ -117,137 +117,6 @@ impl From> for VerificationResult { } } -macro_rules! feature_gate { - ($name:literal, $type:ident) => {{ - #[cfg(not(feature = $name))] - return Err(Error::JWS(ssi_jws::Error::MissingFeatures($name))); - #[cfg(feature = $name)] - &$type - }}; -} - -pub fn get_proof_suite(proof_type: &str) -> Result<&(dyn ProofSuite + Sync), Error> { - Ok(match proof_type { - "RsaSignature2018" => feature_gate!("rsa", RsaSignature2018), - "Ed25519Signature2018" => feature_gate!("ed25519", Ed25519Signature2018), - "Ed25519Signature2020" => feature_gate!("ed25519", Ed25519Signature2020), - "Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021" => { - feature_gate!( - "tezos", - Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 - ) - } - "P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021" => { - feature_gate!( - "tezos", - P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 - ) - } - "EcdsaSecp256k1Signature2019" => feature_gate!("secp256k1", EcdsaSecp256k1Signature2019), - "EcdsaSecp256k1RecoverySignature2020" => { - feature_gate!("secp256k1", EcdsaSecp256k1RecoverySignature2020) - } - "Eip712Signature2021" => { - feature_gate!("eip", Eip712Signature2021) - } - "EthereumPersonalSignature2021" => { - feature_gate!("eip", EthereumPersonalSignature2021) - } - "EthereumEip712Signature2021" => { - feature_gate!("eip", EthereumEip712Signature2021) - } - "TezosSignature2021" => feature_gate!("tezos", TezosSignature2021), - "TezosJcsSignature2021" => feature_gate!("tezos", TezosJcsSignature2021), - "SolanaSignature2021" => feature_gate!("solana", SolanaSignature2021), - "AleoSignature2021" => { - feature_gate!("aleo", AleoSignature2021) - } - "JsonWebSignature2020" => feature_gate!("w3c", JsonWebSignature2020), - "EcdsaSecp256r1Signature2019" => feature_gate!("secp256r1", EcdsaSecp256r1Signature2019), - _ => return Err(Error::ProofTypeNotImplemented), - }) -} - -fn pick_proof_suite<'a, 'b>( - jwk: &JWK, - verification_method: Option<&'a URI>, -) -> Result<&'b (dyn ProofSuite + Sync), Error> { - let algorithm = jwk.get_algorithm().ok_or(Error::MissingAlgorithm)?; - Ok(match algorithm { - Algorithm::RS256 => feature_gate!("rsa", RsaSignature2018), - Algorithm::PS256 => feature_gate!("rsa", JsonWebSignature2020), - Algorithm::ES384 => feature_gate!("secp384r1", JsonWebSignature2020), - Algorithm::AleoTestnet1Signature => feature_gate!("aleo", AleoSignature2021), - Algorithm::EdDSA | Algorithm::EdBlake2b => match verification_method { - Some(URI::String(ref vm)) - if (vm.starts_with("did:sol:") || vm.starts_with("did:pkh:sol:")) - && vm.ends_with("#SolanaMethod2021") => - { - feature_gate!("solana", SolanaSignature2021) - } - Some(URI::String(ref vm)) - if vm.starts_with("did:tz:") || vm.starts_with("did:pkh:tz:") => - { - if vm.ends_with("#TezosMethod2021") { - feature_gate!("tezos", TezosSignature2021) - } else { - feature_gate!( - "tezos", - Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 - ) - } - } - _ => feature_gate!("ed25519", Ed25519Signature2018), - }, - Algorithm::ES256 | Algorithm::ESBlake2b => match verification_method { - Some(URI::String(ref vm)) - if vm.starts_with("did:tz:") || vm.starts_with("did:pkh:tz:") => - { - if vm.ends_with("#TezosMethod2021") { - feature_gate!("tezos", TezosSignature2021) - } else { - feature_gate!( - "tezos", - P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 - ) - } - } - _ => feature_gate!("secp256r1", EcdsaSecp256r1Signature2019), - }, - Algorithm::ES256K | Algorithm::ESBlake2bK => match verification_method { - Some(URI::String(ref vm)) - if vm.starts_with("did:tz:") || vm.starts_with("did:pkh:tz:") => - { - if vm.ends_with("#TezosMethod2021") { - feature_gate!("tezos", TezosSignature2021) - } else { - feature_gate!("w3c", EcdsaSecp256k1RecoverySignature2020) - } - } - _ => feature_gate!("secp256k1", EcdsaSecp256k1Signature2019), - }, - Algorithm::ES256KR => - { - #[allow(clippy::if_same_then_else)] - if use_eip712sig(jwk) { - feature_gate!("eip", EthereumEip712Signature2021) - } else if use_epsig(jwk) { - feature_gate!("eip", EthereumPersonalSignature2021) - } else { - match verification_method { - Some(URI::String(ref vm)) - if (vm.starts_with("did:ethr:") || vm.starts_with("did:pkh:eth:")) - && vm.ends_with("#Eip712Method2021") => - { - feature_gate!("eip", Eip712Signature2021) - } - _ => feature_gate!("secp256k1", EcdsaSecp256k1RecoverySignature2020), - } - } - } - _ => return Err(Error::ProofTypeNotImplemented), - }) -} // Get current time to millisecond precision if possible pub fn now_ms() -> DateTime { let datetime = Utc::now(); @@ -299,7 +168,7 @@ pub trait ProofSuite { async fn complete( &self, - preparation: ProofPreparation, + preparation: &ProofPreparation, signature: &str, ) -> Result; @@ -338,14 +207,6 @@ pub enum SigningInput { }, } -impl ProofPreparation { - pub async fn complete(self, signature: &str) -> Result { - let proof_type = self.proof.type_.clone(); - let suite = get_proof_suite(&proof_type)?; - suite.complete(self, signature).await - } -} - fn use_eip712sig(key: &JWK) -> bool { // deprecated: allow using unregistered "signTypedData" key operation value to indicate using EthereumEip712Signature2021 if let Some(ref key_ops) = key.key_operations { @@ -370,7 +231,7 @@ fn use_epsig(key: &JWK) -> bool { // verify that it is correct for the given issuer and proof purpose. pub async fn ensure_or_pick_verification_relationship( options: &mut LinkedDataProofOptions, - document: &(dyn LinkedDataDocument + Sync), + document: &dyn LinkedDataDocument, key: &JWK, resolver: &dyn DIDResolver, ) -> Result<(), Error> { @@ -475,11 +336,11 @@ impl LinkedDataProofs { ensure_or_pick_verification_relationship(&mut options, document, key, resolver).await?; // Use type property if present let suite = if let Some(ref type_) = options.type_ { - get_proof_suite(type_)? + type_.clone() } // Otherwise pick proof type based on key and options. else { - pick_proof_suite(key, options.verification_method.as_ref())? + ProofSuiteType::pick(key, options.verification_method.as_ref())? }; suite .sign( @@ -508,11 +369,11 @@ impl LinkedDataProofs { .await?; // Use type property if present let suite = if let Some(ref type_) = options.type_ { - get_proof_suite(type_)? + type_.clone() } // Otherwise pick proof type based on key and options. else { - pick_proof_suite(public_key, options.verification_method.as_ref())? + ProofSuiteType::pick(public_key, options.verification_method.as_ref())? }; suite .prepare( @@ -533,7 +394,7 @@ impl LinkedDataProofs { resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, ) -> Result { - let suite = get_proof_suite(proof.type_.as_str())?; + let suite = &proof.type_; suite .verify(proof, document, resolver, context_loader) .await @@ -565,14 +426,12 @@ async fn to_jws_payload( Ok(data) } -#[allow(clippy::too_many_arguments)] async fn sign( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, key: &JWK, - type_: &str, + type_: ProofSuiteType, algorithm: Algorithm, extra_proof_properties: Option>, ) -> Result { @@ -606,7 +465,7 @@ async fn sign_nojws( options: &LinkedDataProofOptions, context_loader: &mut ContextLoader, key: &JWK, - type_: &str, + type_: ProofSuiteType, algorithm: Algorithm, context_uri: &str, extra_proof_properties: Option>, @@ -629,14 +488,12 @@ async fn sign_nojws( Ok(proof) } -#[allow(clippy::too_many_arguments)] async fn prepare( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, public_key: &JWK, - type_: &str, + type_: ProofSuiteType, algorithm: Algorithm, extra_proof_properties: Option>, ) -> Result { @@ -673,7 +530,7 @@ async fn prepare_nojws( options: &LinkedDataProofOptions, context_loader: &mut ContextLoader, public_key: &JWK, - type_: &str, + type_: ProofSuiteType, algorithm: Algorithm, context_uri: &str, extra_proof_properties: Option>, @@ -697,18 +554,6 @@ async fn prepare_nojws( }) } -async fn complete(preparation: ProofPreparation, signature: &str) -> Result { - complete_proof(preparation, signature).await -} - -async fn complete_proof(preparation: ProofPreparation, signature: &str) -> Result { - let mut proof = preparation.proof; - let jws_header = preparation.jws_header.ok_or(Error::MissingJWSHeader)?; - let jws = ssi_jws::complete_sign_unencoded_payload(jws_header, signature)?; - proof.jws = Some(jws); - Ok(proof) -} - async fn verify( proof: &Proof, document: &(dyn LinkedDataDocument + Sync), @@ -833,7 +678,7 @@ mod tests { key.algorithm = Some(Algorithm::EdBlake2b); let vm = format!("{}#TezosMethod2021", "did:example:foo"); let issue_options = LinkedDataProofOptions { - type_: Some(String::from("TezosSignature2021")), + type_: Some(ProofSuiteType::TezosSignature2021), verification_method: Some(URI::String(vm)), ..Default::default() }; @@ -861,7 +706,7 @@ mod tests { key.algorithm = Some(Algorithm::ESBlake2bK); let vm = format!("{}#TezosMethod2021", "did:example:foo"); let issue_options = LinkedDataProofOptions { - type_: Some(String::from("TezosSignature2021")), + type_: Some(ProofSuiteType::TezosSignature2021), verification_method: Some(URI::String(vm)), ..Default::default() }; @@ -888,7 +733,7 @@ mod tests { key.algorithm = Some(Algorithm::ESBlake2bK); let vm = format!("{}#TezosMethod2021", "did:example:foo"); let issue_options = LinkedDataProofOptions { - type_: Some(String::from("TezosJcsSignature2021")), + type_: Some(ProofSuiteType::TezosJcsSignature2021), verification_method: Some(URI::String(vm)), ..Default::default() }; diff --git a/ssi-ldp/src/proof.rs b/ssi-ldp/src/proof.rs index 5d1c8f9cc..a3e07753d 100644 --- a/ssi-ldp/src/proof.rs +++ b/ssi-ldp/src/proof.rs @@ -20,15 +20,17 @@ macro_rules! assert_local { }; } -#[derive(Debug, Serialize, Deserialize, Clone, Default)] +#[derive(Debug, Serialize, Deserialize, Clone)] #[serde(rename_all = "camelCase")] +// TODO use enum to separate betwen JWS and LD proofs? +// TODO create generics type to allow users to provide their own proof suite that implements ProofSuite pub struct Proof { #[serde(rename = "@context")] // TODO: use consistent types for context #[serde(default, skip_serializing_if = "Value::is_null")] pub context: Value, #[serde(rename = "type")] - pub type_: String, + pub type_: ProofSuiteType, #[serde(skip_serializing_if = "Option::is_none")] pub proof_purpose: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -55,10 +57,20 @@ pub struct Proof { } impl Proof { - pub fn new(type_: &str) -> Self { + pub fn new(type_: ProofSuiteType) -> Self { Self { - type_: type_.to_string(), - ..Self::default() + type_, + context: Value::default(), + proof_purpose: None, + proof_value: None, + challenge: None, + creator: None, + verification_method: None, + created: None, + domain: None, + nonce: None, + jws: None, + property_set: None, } } @@ -180,7 +192,7 @@ pub struct LinkedDataProofOptions { #[serde(skip_serializing_if = "Option::is_none")] #[serde(rename = "type")] /// The type of the proof. Default is an appropriate proof type corresponding to the verification method. - pub type_: Option, + pub type_: Option, #[serde(skip_serializing_if = "Option::is_none")] /// The URI of the verificationMethod used for the proof. If omitted a default /// assertionMethod will be used. @@ -277,34 +289,23 @@ fn verify_proof_consistency(proof: &Proof, dataset: &DataSet) -> Result<(), Erro None, ) .ok_or(Error::MissingType)?; - let type_iri = match type_triple.object { - rdf::Object::IRIRef(rdf::IRIRef(ref iri)) => iri, + let type_iri = match &type_triple.object { + rdf::Object::IRIRef(rdf::IRIRef(iri)) => iri, _ => { return Err(Error::JsonLd(JsonLdError::UnexpectedTriple( type_triple.clone(), ))) } }; - match (proof.type_.as_str(), type_iri.as_str()) { - ("RsaSignature2018", "https://w3id.org/security#RsaSignature2018") => (), - ("Ed25519Signature2018", "https://w3id.org/security#Ed25519Signature2018") => (), - ("Ed25519Signature2020", "https://w3id.org/security#Ed25519Signature2020") => (), - ("EcdsaSecp256k1Signature2019", "https://w3id.org/security#EcdsaSecp256k1Signature2019") => (), - ("EcdsaSecp256r1Signature2019", "https://w3id.org/security#EcdsaSecp256r1Signature2019") => (), - ("EcdsaSecp256k1RecoverySignature2020", "https://identity.foundation/EcdsaSecp256k1RecoverySignature2020#EcdsaSecp256k1RecoverySignature2020") => (), - ("EcdsaSecp256k1RecoverySignature2020", "https://w3id.org/security#EcdsaSecp256k1RecoverySignature2020") => (), - ("JsonWebSignature2020", "https://w3id.org/security#JsonWebSignature2020") => (), - ("EthereumPersonalSignature2021", "https://demo.spruceid.com/ld/epsig/EthereumPersonalSignature2021") => (), - ("EthereumPersonalSignature2021", "https://w3id.org/security#EthereumPersonalSignature2021") => (), - ("Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021", "https://w3id.org/security#Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021") => (), - ("P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021", "https://w3id.org/security#P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021") => (), - ("Eip712Signature2021", "https://w3id.org/security#Eip712Signature2021") => (), - ("TezosSignature2021", "https://w3id.org/security#TezosSignature2021") => (), - ("TezosJcsSignature2021", "https://w3id.org/security#TezosJcsSignature2021") => (), - ("AleoSignature2021", "https://w3id.org/security#AleoSignature2021") => (), - ("SolanaSignature2021", "https://w3id.org/security#SolanaSignature2021") => (), - _ => return Err(Error::JsonLd(JsonLdError::UnexpectedTriple(type_triple.clone()))), - }; + if !proof + .type_ + .associated_contexts() + .contains(&type_iri.as_str()) + { + return Err(Error::JsonLd(JsonLdError::UnexpectedTriple( + type_triple.clone(), + ))); + } let proof_id = &type_triple.subject; graph_ref.match_iri_property( diff --git a/ssi-ldp/src/suites/aleo.rs b/ssi-ldp/src/suites/aleo.rs index 361d40e22..4e92423ac 100644 --- a/ssi-ldp/src/suites/aleo.rs +++ b/ssi-ldp/src/suites/aleo.rs @@ -1,5 +1,4 @@ use super::super::*; -use async_trait::async_trait; use serde_json::Value; use ssi_caips::caip10::BlockchainAccountId; use ssi_dids::did_resolve::{resolve_vm, DIDResolver}; @@ -60,14 +59,10 @@ use std::collections::HashMap as Map; /// [caip-aleo-chain-ref]: https://github.com/ChainAgnostic/CAIPs/pull/84 /// [testnet1]: https://developer.aleo.org/testnet/getting_started/overview/ pub struct AleoSignature2021; -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for AleoSignature2021 { - async fn sign( - &self, +impl AleoSignature2021 { + pub(crate) async fn sign( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, @@ -79,7 +74,7 @@ impl ProofSuite for AleoSignature2021 { } else { serde_json::json!([ALEOVM_CONTEXT.clone()]) }, - ..Proof::new("AleoSignature2021") + ..Proof::new(ProofSuiteType::AleoSignature2021) .with_options(options) .with_properties(extra_proof_properties) }; @@ -90,18 +85,15 @@ impl ProofSuite for AleoSignature2021 { Ok(proof) } - async fn prepare( - &self, + pub(crate) async fn prepare( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, - _public_key: &JWK, extra_proof_properties: Option>, ) -> Result { let proof = Proof { context: serde_json::json!([SOLVM_CONTEXT.clone()]), - ..Proof::new("AleoSignature2021") + ..Proof::new(ProofSuiteType::AleoSignature2021) .with_options(options) .with_properties(extra_proof_properties) }; @@ -113,18 +105,7 @@ impl ProofSuite for AleoSignature2021 { }) } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - let mut proof = preparation.proof; - proof.proof_value = Some(signature.to_string()); - Ok(proof) - } - - async fn verify( - &self, + pub(crate) async fn verify( proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, diff --git a/ssi-ldp/src/suites/eip.rs b/ssi-ldp/src/suites/eip.rs index 6eb61be10..e06537f7c 100644 --- a/ssi-ldp/src/suites/eip.rs +++ b/ssi-ldp/src/suites/eip.rs @@ -1,6 +1,5 @@ use super::super::*; use crate::eip712::TypedData; -use async_trait::async_trait; use serde_json::Value; use ssi_dids::did_resolve::{resolve_vm, DIDResolver}; use ssi_json_ld::ContextLoader; @@ -8,14 +7,10 @@ use ssi_jwk::{ECParams, Params as JWKParams, JWK}; use std::collections::HashMap as Map; pub struct Eip712Signature2021; -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for Eip712Signature2021 { - async fn sign( - &self, +impl Eip712Signature2021 { + pub(crate) async fn sign( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, @@ -23,7 +18,7 @@ impl ProofSuite for Eip712Signature2021 { use k256::ecdsa::signature::Signer; let mut proof = Proof { context: serde_json::json!([EIP712VM_CONTEXT.clone()]), - ..Proof::new("Eip712Signature2021") + ..Proof::new(ProofSuiteType::Eip712Signature2021) .with_options(options) .with_properties(extra_proof_properties) }; @@ -46,18 +41,15 @@ impl ProofSuite for Eip712Signature2021 { Ok(proof) } - async fn prepare( - &self, + pub(crate) async fn prepare( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, - _public_key: &JWK, extra_proof_properties: Option>, ) -> Result { let proof = Proof { context: serde_json::json!([EIP712VM_CONTEXT.clone()]), - ..Proof::new("Eip712Signature2021") + ..Proof::new(ProofSuiteType::Eip712Signature2021) .with_options(options) .with_properties(extra_proof_properties) }; @@ -70,18 +62,7 @@ impl ProofSuite for Eip712Signature2021 { }) } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - let mut proof = preparation.proof; - proof.proof_value = Some(signature.to_string()); - Ok(proof) - } - - async fn verify( - &self, + pub(crate) async fn verify( proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, @@ -138,15 +119,10 @@ impl ProofSuite for Eip712Signature2021 { } pub struct EthereumEip712Signature2021; -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for EthereumEip712Signature2021 { - async fn sign( - &self, +impl EthereumEip712Signature2021 { + pub(crate) async fn sign( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, - _context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -161,7 +137,7 @@ impl ProofSuite for EthereumEip712Signature2021 { } let mut proof = Proof { context: serde_json::json!(ssi_json_ld::EIP712SIG_V1_CONTEXT), - ..Proof::new("EthereumEip712Signature2021") + ..Proof::new(ProofSuiteType::EthereumEip712Signature2021) .with_options(options) .with_properties(props) }; @@ -183,13 +159,9 @@ impl ProofSuite for EthereumEip712Signature2021 { Ok(proof) } - async fn prepare( - &self, + pub(crate) async fn prepare( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, - _context_loader: &mut ContextLoader, - _public_key: &JWK, extra_proof_properties: Option>, ) -> Result { let mut props = extra_proof_properties.clone(); @@ -201,7 +173,7 @@ impl ProofSuite for EthereumEip712Signature2021 { } let proof = Proof { context: serde_json::json!(ssi_json_ld::EIP712SIG_V1_CONTEXT), - ..Proof::new("EthereumEip712Signature2021") + ..Proof::new(ProofSuiteType::EthereumEip712Signature2021) .with_options(options) .with_properties(props) }; @@ -213,22 +185,10 @@ impl ProofSuite for EthereumEip712Signature2021 { }) } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - let mut proof = preparation.proof; - proof.proof_value = Some(signature.to_string()); - Ok(proof) - } - - async fn verify( - &self, + pub(crate) async fn verify( proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, - _context_loader: &mut ContextLoader, ) -> Result { let sig_hex = proof .proof_value @@ -278,14 +238,10 @@ impl ProofSuite for EthereumEip712Signature2021 { } pub struct EthereumPersonalSignature2021; -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for EthereumPersonalSignature2021 { - async fn sign( - &self, +impl EthereumPersonalSignature2021 { + pub(crate) async fn sign( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, @@ -293,7 +249,7 @@ impl ProofSuite for EthereumPersonalSignature2021 { use k256::ecdsa::signature::Signer; let mut proof = Proof { context: serde_json::json!([EPSIG_CONTEXT.clone()]), - ..Proof::new("EthereumPersonalSignature2021") + ..Proof::new(ProofSuiteType::EthereumPersonalSignature2021) .with_options(options) .with_properties(extra_proof_properties) }; @@ -316,18 +272,15 @@ impl ProofSuite for EthereumPersonalSignature2021 { Ok(proof) } - async fn prepare( - &self, + pub(crate) async fn prepare( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, - _public_key: &JWK, extra_proof_properties: Option>, ) -> Result { let proof = Proof { context: serde_json::json!([EPSIG_CONTEXT.clone()]), - ..Proof::new("EthereumPersonalSignature2021") + ..Proof::new(ProofSuiteType::EthereumPersonalSignature2021) .with_options(options) .with_properties(extra_proof_properties) }; @@ -342,18 +295,7 @@ impl ProofSuite for EthereumPersonalSignature2021 { }) } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - let mut proof = preparation.proof; - proof.proof_value = Some(signature.to_string()); - Ok(proof) - } - - async fn verify( - &self, + pub(crate) async fn verify( proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, diff --git a/ssi-ldp/src/suites/mod.rs b/ssi-ldp/src/suites/mod.rs index 3653eace3..9438ff675 100644 --- a/ssi-ldp/src/suites/mod.rs +++ b/ssi-ldp/src/suites/mod.rs @@ -2,18 +2,825 @@ mod aleo; #[cfg(feature = "eip")] mod eip; +#[cfg(feature = "secp256k1")] +mod secp256k1; #[cfg(feature = "solana")] mod solana; #[cfg(feature = "tezos")] mod tezos; +#[cfg(feature = "w3c")] mod w3c; #[cfg(feature = "aleo")] -pub use aleo::*; +use aleo::*; #[cfg(feature = "eip")] -pub use eip::*; +use eip::*; +#[cfg(feature = "secp256k1")] +use secp256k1::*; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; #[cfg(feature = "solana")] -pub use solana::*; +use solana::*; +use ssi_core::uri::URI; +use ssi_dids::did_resolve::DIDResolver; +use ssi_json_ld::ContextLoader; +use ssi_jwk::{Algorithm, JWK}; +use ssi_jws::VerificationWarnings; #[cfg(feature = "tezos")] -pub use tezos::*; -pub use w3c::*; +use tezos::*; +#[cfg(feature = "w3c")] +use w3c::*; + +use crate::{ + prepare, prepare_nojws, sign, sign_nojws, use_eip712sig, use_epsig, verify, verify_nojws, + Error, LinkedDataDocument, LinkedDataProofOptions, Proof, ProofPreparation, ProofSuite, +}; + +use async_trait::async_trait; +use std::{collections::HashMap as Map, str::FromStr}; + +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] +pub enum ProofSuiteType { + #[cfg(feature = "rsa")] + RsaSignature2018, + #[cfg(feature = "ed25519")] + Ed25519Signature2018, + #[cfg(feature = "ed25519")] + Ed25519Signature2020, + #[cfg(feature = "tezos")] + Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021, + #[cfg(feature = "tezos")] + P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021, + #[cfg(feature = "secp256k1")] + EcdsaSecp256k1Signature2019, + #[cfg(feature = "secp256k1")] + EcdsaSecp256k1RecoverySignature2020, + #[cfg(feature = "eip")] + Eip712Signature2021, + #[cfg(feature = "eip")] + EthereumPersonalSignature2021, + #[cfg(feature = "eip")] + EthereumEip712Signature2021, + #[cfg(feature = "tezos")] + TezosSignature2021, + #[cfg(feature = "tezos")] + TezosJcsSignature2021, + #[cfg(feature = "solana")] + SolanaSignature2021, + #[cfg(feature = "aleo")] + AleoSignature2021, + #[cfg(feature = "w3c")] + JsonWebSignature2020, + #[cfg(feature = "secp256r1")] + EcdsaSecp256r1Signature2019, + CLSignature2019, + #[cfg(feature = "test")] + NonJwsProof, + #[cfg(feature = "test")] + #[serde(rename = "ex:AnonCredPresentationProofv1")] + AnonCredPresentationProofv1, + #[cfg(feature = "test")] + #[serde(rename = "ex:AnonCredDerivedCredentialv1")] + AnonCredDerivedCredentialv1, +} + +// #[derive(Debug, Error)] +// #[error(transparent)] +// pub struct ParseProofSuiteError(#[from] ErrorRepr); +impl FromStr for ProofSuiteType { + type Err = serde_json::Error; + + fn from_str(s: &str) -> Result { + serde_json::from_value(json!(format!("{s}"))) + } +} + +pub enum SignatureType { + JWS, + LD, +} + +impl ProofSuiteType { + pub fn signature_type(&self) -> SignatureType { + match self { + #[cfg(feature = "rsa")] + Self::RsaSignature2018 => SignatureType::JWS, + #[cfg(feature = "ed25519")] + Self::Ed25519Signature2018 => SignatureType::JWS, + #[cfg(feature = "ed25519")] + Self::Ed25519Signature2020 => SignatureType::LD, + #[cfg(feature = "tezos")] + Self::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 => SignatureType::JWS, + #[cfg(feature = "tezos")] + Self::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 => SignatureType::JWS, + #[cfg(feature = "secp256k1")] + Self::EcdsaSecp256k1Signature2019 => SignatureType::JWS, + #[cfg(feature = "secp256k1")] + Self::EcdsaSecp256k1RecoverySignature2020 => SignatureType::JWS, + #[cfg(feature = "eip")] + Self::Eip712Signature2021 => SignatureType::LD, + #[cfg(feature = "eip")] + Self::EthereumPersonalSignature2021 => SignatureType::LD, + #[cfg(feature = "eip")] + Self::EthereumEip712Signature2021 => SignatureType::LD, + #[cfg(feature = "tezos")] + Self::TezosSignature2021 => SignatureType::LD, + #[cfg(feature = "tezos")] + Self::TezosJcsSignature2021 => SignatureType::LD, + #[cfg(feature = "solana")] + Self::SolanaSignature2021 => SignatureType::LD, + #[cfg(feature = "aleo")] + Self::AleoSignature2021 => SignatureType::LD, + #[cfg(feature = "w3c")] + Self::JsonWebSignature2020 => SignatureType::JWS, + #[cfg(feature = "secp256r1")] + Self::EcdsaSecp256r1Signature2019 => SignatureType::JWS, + Self::CLSignature2019 => todo!(), + #[cfg(feature = "test")] + Self::NonJwsProof + | Self::AnonCredPresentationProofv1 + | Self::AnonCredDerivedCredentialv1 => todo!(), + } + } + + // TODO not sure why this check isn't covered by JSON-LD + pub(crate) fn associated_contexts(&self) -> &[&str] { + match self { +#[cfg(feature = "rsa")] +Self::RsaSignature2018 => &["https://w3id.org/security#RsaSignature2018"], +#[cfg(feature = "ed25519")] +Self::Ed25519Signature2018 => &["https://w3id.org/security#Ed25519Signature2018"], +#[cfg(feature = "ed25519")] +Self::Ed25519Signature2020 => &["https://w3id.org/security#Ed25519Signature2020"], +#[cfg(feature = "tezos")] +Self::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 => { + &["https://w3id.org/security#Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021"] +} +#[cfg(feature = "tezos")] +Self::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 => { + &["https://w3id.org/security#P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021"] +} +#[cfg(feature = "secp256k1")] +Self::EcdsaSecp256k1Signature2019 => &["https://w3id.org/security#EcdsaSecp256k1Signature2019"], +#[cfg(feature = "secp256k1")] +Self::EcdsaSecp256k1RecoverySignature2020 => { + &["https://identity.foundation/EcdsaSecp256k1RecoverySignature2020#EcdsaSecp256k1RecoverySignature2020"] +} +#[cfg(feature = "eip")] +Self::Eip712Signature2021 => &["https://w3id.org/security#Eip712Signature2021"], +#[cfg(feature = "eip")] +Self::EthereumPersonalSignature2021 => &["https://w3id.org/security#EthereumPersonalSignature2021", "https://demo.spruceid.com/ld/epsig/EthereumPersonalSignature2021"], +#[cfg(feature = "eip")] +Self::EthereumEip712Signature2021 => &[], +#[cfg(feature = "tezos")] +Self::TezosSignature2021 => &["https://w3id.org/security#TezosSignature2021"], +#[cfg(feature = "tezos")] +Self::TezosJcsSignature2021 => &["https://w3id.org/security#TezosJcsSignature2021"], +#[cfg(feature = "solana")] +Self::SolanaSignature2021 => &["https://w3id.org/security#SolanaSignature2021"], +#[cfg(feature = "aleo")] +Self::AleoSignature2021 => &["https://w3id.org/security#AleoSignature2021"], +#[cfg(feature = "w3c")] +Self::JsonWebSignature2020 => &["https://w3id.org/security#JsonWebSignature2020"], +#[cfg(feature = "secp256r1")] +Self::EcdsaSecp256r1Signature2019 => &["https://w3id.org/security#EcdsaSecp256r1Signature2019"], + Self::CLSignature2019 => todo!(), + #[cfg(feature = "test")] + Self::NonJwsProof | + Self::AnonCredPresentationProofv1 | Self::AnonCredDerivedCredentialv1 => todo!(), + } + } + + pub(crate) fn pick(jwk: &JWK, verification_method: Option<&URI>) -> Result { + let algorithm = jwk.get_algorithm().ok_or(Error::MissingAlgorithm)?; + Ok(match algorithm { + #[cfg(feature = "rsa")] + Algorithm::RS256 => Self::RsaSignature2018, + #[cfg(feature = "w3c")] + Algorithm::PS256 => Self::JsonWebSignature2020, + #[cfg(feature = "w3c")] + Algorithm::ES384 => Self::JsonWebSignature2020, + #[cfg(feature = "aleo")] + Algorithm::AleoTestnet1Signature => Self::AleoSignature2021, + Algorithm::EdDSA | Algorithm::EdBlake2b => match verification_method { + #[cfg(feature = "solana")] + Some(URI::String(ref vm)) + if (vm.starts_with("did:sol:") || vm.starts_with("did:pkh:sol:")) + && vm.ends_with("#SolanaMethod2021") => + { + Self::SolanaSignature2021 + } + #[cfg(feature = "tezos")] + Some(URI::String(ref vm)) + if vm.starts_with("did:tz:") || vm.starts_with("did:pkh:tz:") => + { + if vm.ends_with("#TezosMethod2021") { + Self::TezosSignature2021 + } else { + Self::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 + } + } + #[cfg(feature = "ed25519")] + _ => Self::Ed25519Signature2018, + #[cfg(not(feature = "ed25519"))] + _ => { + return Err(Error::JWS(ssi_jws::Error::MissingFeatures( + "ed25519 or tezos or solana", + ))) + } + }, + Algorithm::ES256 | Algorithm::ESBlake2b => match verification_method { + #[cfg(feature = "tezos")] + Some(URI::String(ref vm)) + if vm.starts_with("did:tz:") || vm.starts_with("did:pkh:tz:") => + { + if vm.ends_with("#TezosMethod2021") { + Self::TezosSignature2021 + } else { + Self::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 + } + } + #[cfg(feature = "secp256r1")] + _ => Self::EcdsaSecp256r1Signature2019, + #[cfg(not(feature = "secp256r1"))] + _ => { + return Err(Error::JWS(ssi_jws::Error::MissingFeatures( + "secp256r1 or tezos", + ))) + } + }, + Algorithm::ES256K | Algorithm::ESBlake2bK => match verification_method { + #[cfg(any(feature = "tezos", feature = "w3c"))] + Some(URI::String(ref vm)) + if vm.starts_with("did:tz:") || vm.starts_with("did:pkh:tz:") => + { + #[cfg(feature = "tezos")] + if vm.ends_with("#TezosMethod2021") { + return Ok(Self::TezosSignature2021); + } + #[cfg(feature = "w3c")] + return Ok(Self::EcdsaSecp256k1RecoverySignature2020); + #[cfg(not(feature = "w3c"))] + return Err(Error::JWS(ssi_jws::Error::MissingFeatures("w3c or tezos"))); + } + #[cfg(feature = "secp256k1")] + _ => Self::EcdsaSecp256k1Signature2019, + #[cfg(not(feature = "secp256k1"))] + _ => { + return Err(Error::JWS(ssi_jws::Error::MissingFeatures( + "secp256k1 or tezos or w3c", + ))) + } + }, + Algorithm::ES256KR => { + // #[allow(clippy::if_same_then_else)] + #[cfg(feature = "eip")] + if use_eip712sig(jwk) { + return Ok(Self::EthereumEip712Signature2021); + } + #[cfg(feature = "eip")] + if use_epsig(jwk) { + return Ok(Self::EthereumPersonalSignature2021); + } + match verification_method { + #[cfg(feature = "eip")] + Some(URI::String(ref vm)) + if (vm.starts_with("did:ethr:") || vm.starts_with("did:pkh:eth:")) + && vm.ends_with("#Eip712Method2021") => + { + Self::Eip712Signature2021 + } + #[cfg(feature = "secp256k1")] + _ => Self::EcdsaSecp256k1RecoverySignature2020, + #[cfg(not(feature = "secp256k1"))] + _ => { + return Err(Error::JWS(ssi_jws::Error::MissingFeatures( + "secp256k1 or eip", + ))) + } + } + } + _ => return Err(Error::ProofTypeNotSupported), + }) + } + + pub fn is_zkp(&self) -> bool { + matches!(self, Self::CLSignature2019) + } +} + +#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] +#[cfg_attr(not(target_arch = "wasm32"), async_trait)] +impl ProofSuite for ProofSuiteType { + async fn sign( + &self, + document: &(dyn LinkedDataDocument + Sync), + options: &LinkedDataProofOptions, + resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, + key: &JWK, + extra_proof_properties: Option>, + ) -> Result { + match self { + #[cfg(feature = "rsa")] + Self::RsaSignature2018 => { + sign( + document, + options, + context_loader, + key, + self.clone(), + Algorithm::RS256, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "ed25519")] + Self::Ed25519Signature2018 => { + sign( + document, + options, + context_loader, + key, + self.clone(), + Algorithm::EdDSA, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "ed25519")] + Self::Ed25519Signature2020 => { + sign_nojws( + document, + options, + context_loader, + key, + self.clone(), + Algorithm::EdDSA, + ssi_json_ld::W3ID_ED2020_V1_CONTEXT, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "tezos")] + Self::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 => { + Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021::sign( + document, + options, + context_loader, + key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "tezos")] + Self::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 => { + P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021::sign( + document, + options, + context_loader, + key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "secp256k1")] + Self::EcdsaSecp256k1Signature2019 => { + sign( + document, + options, + context_loader, + key, + self.clone(), + Algorithm::ES256K, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "secp256k1")] + Self::EcdsaSecp256k1RecoverySignature2020 => { + EcdsaSecp256k1RecoverySignature2020 + .sign( + document, + options, + resolver, + context_loader, + key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "eip")] + Self::Eip712Signature2021 => { + Eip712Signature2021::sign( + document, + options, + context_loader, + key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "eip")] + Self::EthereumPersonalSignature2021 => { + EthereumPersonalSignature2021::sign( + document, + options, + context_loader, + key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "eip")] + Self::EthereumEip712Signature2021 => { + EthereumEip712Signature2021::sign(document, options, key, extra_proof_properties) + .await + } + #[cfg(feature = "tezos")] + Self::TezosSignature2021 => { + TezosSignature2021::sign( + document, + options, + context_loader, + key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "tezos")] + Self::TezosJcsSignature2021 => { + TezosJcsSignature2021::sign( + document, + options, + context_loader, + key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "solana")] + Self::SolanaSignature2021 => { + SolanaSignature2021::sign( + document, + options, + context_loader, + key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "aleo")] + Self::AleoSignature2021 => { + AleoSignature2021::sign( + document, + options, + context_loader, + key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "w3c")] + Self::JsonWebSignature2020 => { + JsonWebSignature2020::sign( + document, + options, + context_loader, + key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "secp256r1")] + Self::EcdsaSecp256r1Signature2019 => { + sign( + document, + options, + context_loader, + key, + self.clone(), + Algorithm::ES256, + extra_proof_properties, + ) + .await + } + Self::CLSignature2019 => todo!(), + #[cfg(feature = "test")] + Self::NonJwsProof + | Self::AnonCredPresentationProofv1 + | Self::AnonCredDerivedCredentialv1 => todo!(), + } + } + + async fn prepare( + &self, + document: &(dyn LinkedDataDocument + Sync), + options: &LinkedDataProofOptions, + resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, + public_key: &JWK, + extra_proof_properties: Option>, + ) -> Result { + match self { + #[cfg(feature = "rsa")] + Self::RsaSignature2018 => { + prepare( + document, + options, + context_loader, + public_key, + self.clone(), + Algorithm::RS256, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "ed25519")] + Self::Ed25519Signature2018 => { + prepare( + document, + options, + context_loader, + public_key, + self.clone(), + Algorithm::EdDSA, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "ed25519")] + Self::Ed25519Signature2020 => { + prepare_nojws( + document, + options, + context_loader, + public_key, + self.clone(), + Algorithm::EdDSA, + ssi_json_ld::W3ID_ED2020_V1_CONTEXT, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "tezos")] + Self::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 => { + Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021::prepare( + document, + options, + context_loader, + public_key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "tezos")] + Self::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 => { + P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021::prepare( + document, + options, + context_loader, + public_key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "secp256k1")] + Self::EcdsaSecp256k1Signature2019 => { + prepare( + document, + options, + context_loader, + public_key, + self.clone(), + Algorithm::ES256K, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "secp256k1")] + Self::EcdsaSecp256k1RecoverySignature2020 => { + EcdsaSecp256k1RecoverySignature2020 + .prepare( + document, + options, + resolver, + context_loader, + public_key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "eip")] + Self::Eip712Signature2021 => { + Eip712Signature2021::prepare( + document, + options, + context_loader, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "eip")] + Self::EthereumPersonalSignature2021 => { + EthereumPersonalSignature2021::prepare( + document, + options, + context_loader, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "eip")] + Self::EthereumEip712Signature2021 => { + EthereumEip712Signature2021::prepare(document, options, extra_proof_properties) + .await + } + #[cfg(feature = "tezos")] + Self::TezosSignature2021 => { + TezosSignature2021::prepare( + document, + options, + context_loader, + public_key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "tezos")] + Self::TezosJcsSignature2021 => { + TezosJcsSignature2021::prepare( + document, + options, + public_key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "solana")] + Self::SolanaSignature2021 => { + SolanaSignature2021::prepare( + document, + options, + context_loader, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "aleo")] + Self::AleoSignature2021 => { + AleoSignature2021::prepare( + document, + options, + context_loader, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "w3c")] + Self::JsonWebSignature2020 => { + JsonWebSignature2020::prepare( + document, + options, + context_loader, + public_key, + extra_proof_properties, + ) + .await + } + #[cfg(feature = "secp256r1")] + Self::EcdsaSecp256r1Signature2019 => { + prepare( + document, + options, + context_loader, + public_key, + self.clone(), + Algorithm::ES256, + extra_proof_properties, + ) + .await + } + Self::CLSignature2019 => todo!(), + #[cfg(feature = "test")] + Self::NonJwsProof + | Self::AnonCredPresentationProofv1 + | Self::AnonCredDerivedCredentialv1 => todo!(), + } + } + + async fn verify( + &self, + proof: &Proof, + document: &(dyn LinkedDataDocument + Sync), + resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, + ) -> Result { + match self { + #[cfg(feature = "rsa")] + Self::RsaSignature2018 => verify(proof, document, resolver, context_loader).await, + #[cfg(feature = "ed25519")] + Self::Ed25519Signature2018 => verify(proof, document, resolver, context_loader).await, + #[cfg(feature = "ed25519")] + Self::Ed25519Signature2020 => { + verify_nojws(proof, document, resolver, context_loader, Algorithm::EdDSA).await + } + #[cfg(feature = "tezos")] + Self::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 => { + Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021::verify( + proof, + document, + resolver, + context_loader, + ) + .await + } + #[cfg(feature = "tezos")] + Self::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 => { + P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021::verify( + proof, + document, + resolver, + context_loader, + ) + .await + } + #[cfg(feature = "secp256k1")] + Self::EcdsaSecp256k1Signature2019 => { + verify(proof, document, resolver, context_loader).await + } + #[cfg(feature = "secp256k1")] + Self::EcdsaSecp256k1RecoverySignature2020 => { + EcdsaSecp256k1RecoverySignature2020 + .verify(proof, document, resolver, context_loader) + .await + } + #[cfg(feature = "eip")] + Self::Eip712Signature2021 => { + Eip712Signature2021::verify(proof, document, resolver, context_loader).await + } + #[cfg(feature = "eip")] + Self::EthereumPersonalSignature2021 => { + EthereumPersonalSignature2021::verify(proof, document, resolver, context_loader) + .await + } + #[cfg(feature = "eip")] + Self::EthereumEip712Signature2021 => { + EthereumEip712Signature2021::verify(proof, document, resolver).await + } + #[cfg(feature = "tezos")] + Self::TezosSignature2021 => { + TezosSignature2021::verify(proof, document, resolver, context_loader).await + } + #[cfg(feature = "tezos")] + Self::TezosJcsSignature2021 => { + TezosJcsSignature2021::verify(proof, document, resolver).await + } + #[cfg(feature = "solana")] + Self::SolanaSignature2021 => { + SolanaSignature2021 + .verify(proof, document, resolver, context_loader) + .await + } + #[cfg(feature = "aleo")] + Self::AleoSignature2021 => { + AleoSignature2021::verify(proof, document, resolver, context_loader).await + } + #[cfg(feature = "w3c")] + Self::JsonWebSignature2020 => { + JsonWebSignature2020::verify(proof, document, resolver, context_loader).await + } + #[cfg(feature = "secp256r1")] + Self::EcdsaSecp256r1Signature2019 => { + verify(proof, document, resolver, context_loader).await + } + Self::CLSignature2019 => todo!(), + #[cfg(feature = "test")] + Self::NonJwsProof + | Self::AnonCredPresentationProofv1 + | Self::AnonCredDerivedCredentialv1 => todo!(), + } + } + + async fn complete( + &self, + preparation: &ProofPreparation, + signature: &str, + ) -> Result { + let mut proof = preparation.proof.clone(); + match self.signature_type() { + SignatureType::LD => { + proof.proof_value = Some(signature.to_string()); + } + SignatureType::JWS => { + let jws_header = preparation + .jws_header + .as_ref() + .ok_or(Error::MissingJWSHeader)?; + let jws = ssi_jws::complete_sign_unencoded_payload(jws_header, signature)?; + proof.jws = Some(jws); + } + } + Ok(proof) + } +} diff --git a/ssi-ldp/src/suites/secp256k1.rs b/ssi-ldp/src/suites/secp256k1.rs new file mode 100644 index 000000000..fd2c26aa8 --- /dev/null +++ b/ssi-ldp/src/suites/secp256k1.rs @@ -0,0 +1,96 @@ +use super::super::*; +use serde_json::Value; +use ssi_dids::did_resolve::{resolve_vm, DIDResolver}; +use ssi_json_ld::ContextLoader; +use ssi_jwk::{Algorithm, JWK}; +use std::collections::HashMap as Map; + +#[cfg(feature = "secp256k1")] +pub struct EcdsaSecp256k1RecoverySignature2020; +#[cfg(feature = "secp256k1")] +impl EcdsaSecp256k1RecoverySignature2020 { + pub(crate) async fn sign( + &self, + document: &(dyn LinkedDataDocument + Sync), + options: &LinkedDataProofOptions, + _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, + key: &JWK, + extra_proof_properties: Option>, + ) -> Result { + if let Some(key_algorithm) = key.algorithm { + if key_algorithm != Algorithm::ES256KR { + return Err(Error::JWS(ssi_jws::Error::AlgorithmMismatch)); + } + } + let has_context = document_has_context(document, ssi_json_ld::W3ID_ESRS2020_V2_CONTEXT)?; + let proof = Proof { + context: if has_context { + Value::Null + } else { + serde_json::json!([ssi_json_ld::W3ID_ESRS2020_V2_CONTEXT]) + }, + ..Proof::new(ProofSuiteType::EcdsaSecp256k1RecoverySignature2020) + .with_options(options) + .with_properties(extra_proof_properties) + }; + sign_proof(document, proof, key, Algorithm::ES256KR, context_loader).await + } + + pub(crate) async fn prepare( + &self, + document: &(dyn LinkedDataDocument + Sync), + options: &LinkedDataProofOptions, + _resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, + _public_key: &JWK, + extra_proof_properties: Option>, + ) -> Result { + let has_context = document_has_context(document, ssi_json_ld::W3ID_ESRS2020_V2_CONTEXT)?; + let proof = Proof { + context: if has_context { + Value::Null + } else { + serde_json::json!([ssi_json_ld::W3ID_ESRS2020_V2_CONTEXT]) + }, + ..Proof::new(ProofSuiteType::EcdsaSecp256k1RecoverySignature2020) + .with_options(options) + .with_properties(extra_proof_properties) + }; + prepare_proof(document, proof, Algorithm::ES256KR, context_loader).await + } + + pub(crate) async fn verify( + &self, + proof: &Proof, + document: &(dyn LinkedDataDocument + Sync), + resolver: &dyn DIDResolver, + context_loader: &mut ContextLoader, + ) -> Result { + let jws = proof.jws.as_ref().ok_or(Error::MissingProofSignature)?; + let verification_method = proof + .verification_method + .as_ref() + .ok_or(Error::MissingVerificationMethod)?; + let vm = resolve_vm(verification_method, resolver).await?; + if vm.type_ != "EcdsaSecp256k1RecoveryMethod2020" + && vm.type_ != "EcdsaSecp256k1VerificationKey2019" + && vm.type_ != "JsonWebKey2020" + { + return Err(Error::VerificationMethodMismatch); + } + let message = to_jws_payload(document, proof, context_loader).await?; + let (_header, jwk) = ssi_jws::detached_recover(jws, &message)?; + let mut warnings = VerificationWarnings::default(); + if let Err(_e) = vm.match_jwk(&jwk) { + // Legacy mode: allow using Keccak-256 instead of SHA-256 + let (_header, jwk) = ssi_jws::detached_recover_legacy_keccak_es256kr(jws, &message)?; + vm.match_jwk(&jwk)?; + warnings.push( + "Signature uses legacy mode EcdsaSecp256k1RecoveryMethod2020 with Keccak-256" + .to_string(), + ); + } + Ok(warnings) + } +} diff --git a/ssi-ldp/src/suites/solana.rs b/ssi-ldp/src/suites/solana.rs index a1b7e1743..0a9a6ec4a 100644 --- a/ssi-ldp/src/suites/solana.rs +++ b/ssi-ldp/src/suites/solana.rs @@ -1,5 +1,4 @@ use super::super::*; -use async_trait::async_trait; use serde_json::Value; use ssi_dids::did_resolve::{resolve_vm, DIDResolver}; use ssi_json_ld::ContextLoader; @@ -7,21 +6,17 @@ use ssi_jwk::{Algorithm, Base64urlUInt, JWK}; use std::collections::HashMap as Map; pub struct SolanaSignature2021; -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for SolanaSignature2021 { - async fn sign( - &self, +impl SolanaSignature2021 { + pub(crate) async fn sign( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { let mut proof = Proof { context: serde_json::json!([SOLVM_CONTEXT.clone()]), - ..Proof::new("SolanaSignature2021") + ..Proof::new(ProofSuiteType::SolanaSignature2021) .with_options(options) .with_properties(extra_proof_properties) }; @@ -34,18 +29,15 @@ impl ProofSuite for SolanaSignature2021 { Ok(proof) } - async fn prepare( - &self, + pub(crate) async fn prepare( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, - _public_key: &JWK, extra_proof_properties: Option>, ) -> Result { let proof = Proof { context: serde_json::json!([SOLVM_CONTEXT.clone()]), - ..Proof::new("SolanaSignature2021") + ..Proof::new(ProofSuiteType::SolanaSignature2021) .with_options(options) .with_properties(extra_proof_properties) }; @@ -59,17 +51,7 @@ impl ProofSuite for SolanaSignature2021 { }) } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - let mut proof = preparation.proof; - proof.proof_value = Some(signature.to_string()); - Ok(proof) - } - - async fn verify( + pub(crate) async fn verify( &self, proof: &Proof, document: &(dyn LinkedDataDocument + Sync), diff --git a/ssi-ldp/src/suites/tezos.rs b/ssi-ldp/src/suites/tezos.rs index f33864229..37bcd583f 100644 --- a/ssi-ldp/src/suites/tezos.rs +++ b/ssi-ldp/src/suites/tezos.rs @@ -1,5 +1,4 @@ use super::super::*; -use async_trait::async_trait; use serde_json::Value; use ssi_caips::caip10::BlockchainAccountId; use ssi_dids::did_resolve::{resolve_vm, DIDResolver}; @@ -13,14 +12,10 @@ const P2SIG_PREFIX: [u8; 4] = [54, 240, 44, 52]; /// Proof type used with [did:tz](https://github.com/spruceid/did-tezos/) `tz1` addresses. pub struct Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021; -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { - async fn sign( - &self, +impl Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { + pub(crate) async fn sign( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, @@ -41,18 +36,16 @@ impl ProofSuite for Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { // It needs custom JSON_LD context too. let proof = Proof { context: TZ_CONTEXT.clone(), - ..Proof::new("Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021") + ..Proof::new(ProofSuiteType::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021) .with_options(options) .with_properties(props) }; sign_proof(document, proof, key, Algorithm::EdBlake2b, context_loader).await } - async fn prepare( - &self, + pub(crate) async fn prepare( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, @@ -67,23 +60,14 @@ impl ProofSuite for Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { // It needs custom JSON_LD context too. let proof = Proof { context: TZ_CONTEXT.clone(), - ..Proof::new("Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021") + ..Proof::new(ProofSuiteType::Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021) .with_options(options) .with_properties(props) }; prepare_proof(document, proof, Algorithm::EdBlake2b, context_loader).await } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - complete(preparation, signature).await - } - - async fn verify( - &self, + pub(crate) async fn verify( proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, @@ -112,14 +96,10 @@ impl ProofSuite for Ed25519BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { /// Proof type used with [did:tz](https://github.com/spruceid/did-tezos/) `tz3` addresses. pub struct P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021; -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { - async fn sign( - &self, +impl P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { + pub(crate) async fn sign( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, @@ -139,18 +119,16 @@ impl ProofSuite for P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { // It needs custom JSON_LD context too. let proof = Proof { context: TZ_CONTEXT.clone(), - ..Proof::new("P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021") + ..Proof::new(ProofSuiteType::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021) .with_options(options) .with_properties(props) }; sign_proof(document, proof, key, Algorithm::ESBlake2b, context_loader).await } - async fn prepare( - &self, + pub(crate) async fn prepare( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, @@ -165,23 +143,14 @@ impl ProofSuite for P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021 { // It needs custom JSON_LD context too. let proof = Proof { context: TZ_CONTEXT.clone(), - ..Proof::new("P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021") + ..Proof::new(ProofSuiteType::P256BLAKE2BDigestSize20Base58CheckEncodedSignature2021) .with_options(options) .with_properties(props) }; prepare_proof(document, proof, Algorithm::ESBlake2b, context_loader).await } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - complete(preparation, signature).await - } - - async fn verify( - &self, + pub(crate) async fn verify( proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, @@ -248,14 +217,10 @@ async fn micheline_from_document_and_options_jcs( } pub struct TezosSignature2021; -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for TezosSignature2021 { - async fn sign( - &self, +impl TezosSignature2021 { + pub(crate) async fn sign( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, @@ -268,7 +233,7 @@ impl ProofSuite for TezosSignature2021 { .insert("publicKeyJwk".to_string(), jwk_value); let mut proof = Proof { context: TZVM_CONTEXT.clone(), - ..Proof::new("TezosSignature2021") + ..Proof::new(ProofSuiteType::TezosSignature2021) .with_options(options) .with_properties(props) }; @@ -289,11 +254,9 @@ impl ProofSuite for TezosSignature2021 { Ok(proof) } - async fn prepare( - &self, + pub(crate) async fn prepare( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, @@ -307,7 +270,7 @@ impl ProofSuite for TezosSignature2021 { let proof = Proof { context: TZVM_CONTEXT.clone(), - ..Proof::new("TezosSignature2021") + ..Proof::new(ProofSuiteType::TezosSignature2021) .with_options(options) .with_properties(props) }; @@ -323,18 +286,7 @@ impl ProofSuite for TezosSignature2021 { }) } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - let mut proof = preparation.proof; - proof.proof_value = Some(signature.to_string()); - Ok(proof) - } - - async fn verify( - &self, + pub(crate) async fn verify( proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, @@ -392,14 +344,10 @@ impl ProofSuite for TezosSignature2021 { } pub struct TezosJcsSignature2021; -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for TezosJcsSignature2021 { - async fn sign( - &self, +impl TezosJcsSignature2021 { + pub(crate) async fn sign( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, @@ -413,7 +361,7 @@ impl ProofSuite for TezosJcsSignature2021 { .insert("publicKeyMultibase".to_string(), Value::String(pkmb)); let mut proof = Proof { context: TZJCSVM_CONTEXT.clone(), - ..Proof::new("TezosJcsSignature2021") + ..Proof::new(ProofSuiteType::TezosJcsSignature2021) .with_options(options) .with_properties(props) }; @@ -434,12 +382,9 @@ impl ProofSuite for TezosJcsSignature2021 { Ok(proof) } - async fn prepare( - &self, + pub(crate) async fn prepare( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, - _context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { @@ -454,7 +399,7 @@ impl ProofSuite for TezosJcsSignature2021 { let proof = Proof { context: TZJCSVM_CONTEXT.clone(), - ..Proof::new("TezosJcsSignature2021") + ..Proof::new(ProofSuiteType::TezosJcsSignature2021) .with_options(options) .with_properties(props) }; @@ -469,22 +414,10 @@ impl ProofSuite for TezosJcsSignature2021 { }) } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - let mut proof = preparation.proof; - proof.proof_value = Some(signature.to_string()); - Ok(proof) - } - - async fn verify( - &self, + pub(crate) async fn verify( proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, - _context_loader: &mut ContextLoader, ) -> Result { let sig_bs58 = proof .proof_value diff --git a/ssi-ldp/src/suites/w3c.rs b/ssi-ldp/src/suites/w3c.rs index 32b18dd31..f2c47d599 100644 --- a/ssi-ldp/src/suites/w3c.rs +++ b/ssi-ldp/src/suites/w3c.rs @@ -1,458 +1,22 @@ use super::super::*; -use async_trait::async_trait; use serde_json::Value; -use ssi_dids::did_resolve::{resolve_key, resolve_vm, DIDResolver}; +use ssi_dids::did_resolve::{resolve_key, DIDResolver}; use ssi_json_ld::ContextLoader; use ssi_jwk::{Algorithm, Params as JWKParams, JWK}; use std::collections::HashMap as Map; -#[cfg(feature = "rsa")] -pub struct RsaSignature2018; -#[cfg(feature = "rsa")] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for RsaSignature2018 { - async fn sign( - &self, - document: &(dyn LinkedDataDocument + Sync), - options: &LinkedDataProofOptions, - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - key: &JWK, - extra_proof_properties: Option>, - ) -> Result { - sign( - document, - options, - resolver, - context_loader, - key, - "RsaSignature2018", - Algorithm::RS256, - extra_proof_properties, - ) - .await - } - async fn prepare( - &self, - document: &(dyn LinkedDataDocument + Sync), - options: &LinkedDataProofOptions, - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - public_key: &JWK, - extra_proof_properties: Option>, - ) -> Result { - prepare( - document, - options, - resolver, - context_loader, - public_key, - "RsaSignature2018", - Algorithm::RS256, - extra_proof_properties, - ) - .await - } - async fn verify( - &self, - proof: &Proof, - document: &(dyn LinkedDataDocument + Sync), - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - ) -> Result { - verify(proof, document, resolver, context_loader).await - } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - complete(preparation, signature).await - } -} - -#[cfg(feature = "ed25519")] -pub struct Ed25519Signature2018; -#[cfg(feature = "ed25519")] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for Ed25519Signature2018 { - async fn sign( - &self, - document: &(dyn LinkedDataDocument + Sync), - options: &LinkedDataProofOptions, - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - key: &JWK, - extra_proof_properties: Option>, - ) -> Result { - sign( - document, - options, - resolver, - context_loader, - key, - "Ed25519Signature2018", - Algorithm::EdDSA, - extra_proof_properties, - ) - .await - } - async fn prepare( - &self, - document: &(dyn LinkedDataDocument + Sync), - options: &LinkedDataProofOptions, - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - public_key: &JWK, - extra_proof_properties: Option>, - ) -> Result { - prepare( - document, - options, - resolver, - context_loader, - public_key, - "Ed25519Signature2018", - Algorithm::EdDSA, - extra_proof_properties, - ) - .await - } - async fn verify( - &self, - proof: &Proof, - document: &(dyn LinkedDataDocument + Sync), - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - ) -> Result { - verify(proof, document, resolver, context_loader).await - } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - complete(preparation, signature).await - } -} - -#[cfg(feature = "ed25519")] -pub struct Ed25519Signature2020; -#[cfg(feature = "ed25519")] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for Ed25519Signature2020 { - async fn sign( - &self, - document: &(dyn LinkedDataDocument + Sync), - options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - key: &JWK, - extra_proof_properties: Option>, - ) -> Result { - sign_nojws( - document, - options, - context_loader, - key, - "Ed25519Signature2020", - Algorithm::EdDSA, - ssi_json_ld::W3ID_ED2020_V1_CONTEXT, - extra_proof_properties, - ) - .await - } - async fn verify( - &self, - proof: &Proof, - document: &(dyn LinkedDataDocument + Sync), - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - ) -> Result { - verify_nojws(proof, document, resolver, context_loader, Algorithm::EdDSA).await - } - async fn prepare( - &self, - document: &(dyn LinkedDataDocument + Sync), - options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - public_key: &JWK, - extra_proof_properties: Option>, - ) -> Result { - prepare_nojws( - document, - options, - context_loader, - public_key, - "Ed25519Signature2020", - Algorithm::EdDSA, - ssi_json_ld::W3ID_ED2020_V1_CONTEXT, - extra_proof_properties, - ) - .await - } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - let mut proof = preparation.proof; - proof.proof_value = Some(signature.to_string()); - Ok(proof) - } -} - -#[cfg(feature = "secp256k1")] -pub struct EcdsaSecp256k1Signature2019; -#[cfg(feature = "secp256k1")] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for EcdsaSecp256k1Signature2019 { - async fn sign( - &self, - document: &(dyn LinkedDataDocument + Sync), - options: &LinkedDataProofOptions, - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - key: &JWK, - extra_proof_properties: Option>, - ) -> Result { - sign( - document, - options, - resolver, - context_loader, - key, - "EcdsaSecp256k1Signature2019", - Algorithm::ES256K, - extra_proof_properties, - ) - .await - } - async fn prepare( - &self, - document: &(dyn LinkedDataDocument + Sync), - options: &LinkedDataProofOptions, - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - public_key: &JWK, - extra_proof_properties: Option>, - ) -> Result { - prepare( - document, - options, - resolver, - context_loader, - public_key, - "EcdsaSecp256k1Signature2019", - Algorithm::ES256K, - extra_proof_properties, - ) - .await - } - async fn verify( - &self, - proof: &Proof, - document: &(dyn LinkedDataDocument + Sync), - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - ) -> Result { - verify(proof, document, resolver, context_loader).await - } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - complete(preparation, signature).await - } -} - -#[cfg(feature = "secp256k1")] -pub struct EcdsaSecp256k1RecoverySignature2020; -#[cfg(feature = "secp256k1")] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for EcdsaSecp256k1RecoverySignature2020 { - async fn sign( - &self, - document: &(dyn LinkedDataDocument + Sync), - options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - key: &JWK, - extra_proof_properties: Option>, - ) -> Result { - if let Some(key_algorithm) = key.algorithm { - if key_algorithm != Algorithm::ES256KR { - return Err(Error::JWS(ssi_jws::Error::AlgorithmMismatch)); - } - } - let has_context = document_has_context(document, ssi_json_ld::W3ID_ESRS2020_V2_CONTEXT)?; - let proof = Proof { - context: if has_context { - Value::Null - } else { - serde_json::json!([ssi_json_ld::W3ID_ESRS2020_V2_CONTEXT]) - }, - ..Proof::new("EcdsaSecp256k1RecoverySignature2020") - .with_options(options) - .with_properties(extra_proof_properties) - }; - sign_proof(document, proof, key, Algorithm::ES256KR, context_loader).await - } - - async fn prepare( - &self, - document: &(dyn LinkedDataDocument + Sync), - options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - _public_key: &JWK, - extra_proof_properties: Option>, - ) -> Result { - let has_context = document_has_context(document, ssi_json_ld::W3ID_ESRS2020_V2_CONTEXT)?; - let proof = Proof { - context: if has_context { - Value::Null - } else { - serde_json::json!([ssi_json_ld::W3ID_ESRS2020_V2_CONTEXT]) - }, - ..Proof::new("EcdsaSecp256k1RecoverySignature2020") - .with_options(options) - .with_properties(extra_proof_properties) - }; - prepare_proof(document, proof, Algorithm::ES256KR, context_loader).await - } - - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - complete(preparation, signature).await - } - - async fn verify( - &self, - proof: &Proof, - document: &(dyn LinkedDataDocument + Sync), - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - ) -> Result { - let jws = proof.jws.as_ref().ok_or(Error::MissingProofSignature)?; - let verification_method = proof - .verification_method - .as_ref() - .ok_or(Error::MissingVerificationMethod)?; - let vm = resolve_vm(verification_method, resolver).await?; - if vm.type_ != "EcdsaSecp256k1RecoveryMethod2020" - && vm.type_ != "EcdsaSecp256k1VerificationKey2019" - && vm.type_ != "JsonWebKey2020" - { - return Err(Error::VerificationMethodMismatch); - } - let message = to_jws_payload(document, proof, context_loader).await?; - let (_header, jwk) = ssi_jws::detached_recover(jws, &message)?; - let mut warnings = VerificationWarnings::default(); - if let Err(_e) = vm.match_jwk(&jwk) { - // Legacy mode: allow using Keccak-256 instead of SHA-256 - let (_header, jwk) = ssi_jws::detached_recover_legacy_keccak_es256kr(jws, &message)?; - vm.match_jwk(&jwk)?; - warnings.push( - "Signature uses legacy mode EcdsaSecp256k1RecoveryMethod2020 with Keccak-256" - .to_string(), - ); - } - Ok(warnings) - } -} -#[cfg(feature = "secp256r1")] -pub struct EcdsaSecp256r1Signature2019; -#[cfg(feature = "secp256r1")] -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for EcdsaSecp256r1Signature2019 { - async fn sign( - &self, - document: &(dyn LinkedDataDocument + Sync), - options: &LinkedDataProofOptions, - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - key: &JWK, - extra_proof_properties: Option>, - ) -> Result { - sign( - document, - options, - resolver, - context_loader, - key, - "EcdsaSecp256r1Signature2019", - Algorithm::ES256, - extra_proof_properties, - ) - .await - } - async fn prepare( - &self, - document: &(dyn LinkedDataDocument + Sync), - options: &LinkedDataProofOptions, - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - public_key: &JWK, - extra_proof_properties: Option>, - ) -> Result { - prepare( - document, - options, - resolver, - context_loader, - public_key, - "EcdsaSecp256r1Signature2019", - Algorithm::ES256, - extra_proof_properties, - ) - .await - } - async fn verify( - &self, - proof: &Proof, - document: &(dyn LinkedDataDocument + Sync), - resolver: &dyn DIDResolver, - context_loader: &mut ContextLoader, - ) -> Result { - verify(proof, document, resolver, context_loader).await - } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - complete(preparation, signature).await - } -} - /// pub struct JsonWebSignature2020; -#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] -#[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl ProofSuite for JsonWebSignature2020 { - async fn sign( - &self, +impl JsonWebSignature2020 { + pub(crate) async fn sign( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, key: &JWK, extra_proof_properties: Option>, ) -> Result { let algorithm = key.get_algorithm().ok_or(Error::MissingAlgorithm)?; - self.validate_key_and_algorithm(key, algorithm)?; + Self::validate_key_and_algorithm(key, algorithm)?; let has_context = document_has_context(document, ssi_json_ld::W3ID_JWS2020_V1_CONTEXT)?; let proof = Proof { context: if has_context { @@ -460,23 +24,21 @@ impl ProofSuite for JsonWebSignature2020 { } else { serde_json::json!([ssi_json_ld::W3ID_JWS2020_V1_CONTEXT]) }, - ..Proof::new("JsonWebSignature2020") + ..Proof::new(ProofSuiteType::JsonWebSignature2020) .with_options(options) .with_properties(extra_proof_properties) }; sign_proof(document, proof, key, algorithm, context_loader).await } - async fn prepare( - &self, + pub(crate) async fn prepare( document: &(dyn LinkedDataDocument + Sync), options: &LinkedDataProofOptions, - _resolver: &dyn DIDResolver, context_loader: &mut ContextLoader, public_key: &JWK, extra_proof_properties: Option>, ) -> Result { let algorithm = public_key.get_algorithm().ok_or(Error::MissingAlgorithm)?; - self.validate_key_and_algorithm(public_key, algorithm)?; + Self::validate_key_and_algorithm(public_key, algorithm)?; let has_context = document_has_context(document, ssi_json_ld::W3ID_JWS2020_V1_CONTEXT)?; let proof = Proof { context: if has_context { @@ -484,14 +46,13 @@ impl ProofSuite for JsonWebSignature2020 { } else { serde_json::json!([ssi_json_ld::W3ID_JWS2020_V1_CONTEXT]) }, - ..Proof::new("JsonWebSignature2020") + ..Proof::new(ProofSuiteType::JsonWebSignature2020) .with_options(options) .with_properties(extra_proof_properties) }; prepare_proof(document, proof, algorithm, context_loader).await } - async fn verify( - &self, + pub(crate) async fn verify( proof: &Proof, document: &(dyn LinkedDataDocument + Sync), resolver: &dyn DIDResolver, @@ -511,9 +72,9 @@ impl ProofSuite for JsonWebSignature2020 { signature, } = ssi_jws::decode_jws_parts(header_b64, &message, signature_b64)?; // Redundant early algorithm check before expensive key lookup and signature verification. - self.validate_algorithm(header.algorithm)?; + Self::validate_algorithm(header.algorithm)?; let key = resolve_key(verification_method, resolver).await?; - self.validate_key_and_algorithm(&key, header.algorithm)?; + Self::validate_key_and_algorithm(&key, header.algorithm)?; Ok(ssi_jws::verify_bytes_warnable( header.algorithm, &signing_input, @@ -521,17 +82,8 @@ impl ProofSuite for JsonWebSignature2020 { &signature, )?) } - async fn complete( - &self, - preparation: ProofPreparation, - signature: &str, - ) -> Result { - complete(preparation, signature).await - } -} -impl JsonWebSignature2020 { - fn validate_algorithm(&self, algorithm: Algorithm) -> Result<(), Error> { + fn validate_algorithm(algorithm: Algorithm) -> Result<(), Error> { match algorithm { Algorithm::EdDSA => (), Algorithm::ES256K => (), @@ -543,7 +95,7 @@ impl JsonWebSignature2020 { Ok(()) } // https://w3c-ccg.github.io/lds-jws2020/#jose-conformance - fn validate_key_and_algorithm(&self, key: &JWK, algorithm: Algorithm) -> Result<(), Error> { + fn validate_key_and_algorithm(key: &JWK, algorithm: Algorithm) -> Result<(), Error> { if let Some(key_algorithm) = key.algorithm { if key_algorithm != algorithm { return Err(Error::JWS(ssi_jws::Error::AlgorithmMismatch)); diff --git a/ssi-vc/src/lib.rs b/ssi-vc/src/lib.rs index a9a838340..3b821186d 100644 --- a/ssi-vc/src/lib.rs +++ b/ssi-vc/src/lib.rs @@ -909,9 +909,7 @@ impl Credential { pub fn is_zkp(&self) -> bool { match &self.proof { - Some(proofs) => proofs - .into_iter() - .any(|proof| proof.type_.contains(&"CLSignature2019".to_string())), + Some(proofs) => proofs.into_iter().any(|proof| proof.type_.is_zkp()), _ => false, } } @@ -1815,7 +1813,7 @@ pub(crate) mod tests { use ssi_dids::did_resolve::DereferencingInputMetadata; use ssi_dids::{example::DIDExample, VerificationMethodMap}; use ssi_json_ld::urdna2015; - use ssi_ldp::{suites::*, ProofSuite}; + use ssi_ldp::{ProofSuite, ProofSuiteType}; #[test] fn numeric_date() { @@ -2302,7 +2300,12 @@ pub(crate) mod tests { }; let sig = ssi_jws::sign_bytes(algorithm, signing_input, &key).unwrap(); let sig_b64 = base64::encode_config(sig, base64::URL_SAFE_NO_PAD); - let proof = preparation.complete(&sig_b64).await.unwrap(); + let proof = preparation + .proof + .type_ + .complete(&preparation, &sig_b64) + .await + .unwrap(); println!("{}", serde_json::to_string_pretty(&proof).unwrap()); vc.add_proof(proof); vc.validate().unwrap(); @@ -2438,7 +2441,10 @@ _:c14n0 vc, + Err(_) => return, + }; let result = vc.verify(None, &DIDExample, context_loader).await; println!("{:#?}", result); assert!(!result.errors.is_empty()); @@ -3120,7 +3126,7 @@ _:c14n0