From 909c7dbde37074fdb6a121f1f11eb345739d5c50 Mon Sep 17 00:00:00 2001 From: Simon Bihel Date: Thu, 21 Sep 2023 19:13:45 +0100 Subject: [PATCH] Update RustCrypto/signature crates Mostly to upgrade ed25519-dalek which has a vulnerability. The impact should be minimal, but does include empty error messages when recovered addresses don't match. This was to avoid breaking changes, and it should be addressed after the upcoming major refactor. --- did-key/Cargo.toml | 10 +- ssi-crypto/Cargo.toml | 8 +- ssi-jwk/Cargo.toml | 32 ++-- ssi-jwk/src/lib.rs | 66 ++++----- ssi-jws/Cargo.toml | 33 +++-- ssi-jws/src/lib.rs | 299 +++++++++++++++++++++++--------------- ssi-ldp/Cargo.toml | 29 ++-- ssi-ldp/src/eip712.rs | 2 +- ssi-ldp/src/suites/eip.rs | 80 +++++----- ssi-tzkey/Cargo.toml | 10 +- ssi-tzkey/src/lib.rs | 10 +- ssi-vc/Cargo.toml | 23 ++- ssi-vc/src/cacao.rs | 15 +- ssi-vc/src/lib.rs | 10 +- 14 files changed, 367 insertions(+), 260 deletions(-) diff --git a/did-key/Cargo.toml b/did-key/Cargo.toml index 357c2632b..52dceab5f 100644 --- a/did-key/Cargo.toml +++ b/did-key/Cargo.toml @@ -19,13 +19,15 @@ secp384r1 = ["ssi-jwk/secp384r1"] [dependencies] ssi-dids = { path = "../ssi-dids", version = "0.1" } -ssi-jwk = { path = "../ssi-jwk", version = "0.1", default-features = false, features = ["ripemd-160"] } -ssi-crypto = { path = "../ssi-crypto", default-features = false, version = "0.1"} +ssi-jwk = { path = "../ssi-jwk", version = "0.1", default-features = false, features = [ + "ripemd-160", +] } +ssi-crypto = { path = "../ssi-crypto", default-features = false, version = "0.1" } async-trait = "0.1" thiserror = "1.0" multibase = "0.8" -k256 = { version = "0.11", optional = true, features = ["ecdsa"] } -p256 = { version = "0.11", optional = true, features = ["ecdsa"] } +k256 = { version = "0.13.1", optional = true, features = ["ecdsa"] } +p256 = { version = "0.13.2", optional = true, features = ["ecdsa"] } serde_json = "1.0" simple_asn1 = "^0.5.2" diff --git a/ssi-crypto/Cargo.toml b/ssi-crypto/Cargo.toml index abfacf016..6adbb5462 100644 --- a/ssi-crypto/Cargo.toml +++ b/ssi-crypto/Cargo.toml @@ -10,7 +10,7 @@ documentation = "https://docs.rs/ssi-crypto/" [features] default = ["secp256k1", "ripemd-160"] -secp256k1 = ["k256", "k256/keccak256", "keccak"] +secp256k1 = ["k256", "keccak"] bbs = ["dep:bbs", "pairing-plus", "rand_old", "sha2_old", "hkdf", "serde"] ripemd-160 = ["ripemd160", "secp256k1", "bs58"] keccak = ["keccak-hash"] @@ -20,13 +20,13 @@ ring = ["dep:ring"] thiserror = "1.0" sha2 = { version = "0.10" } ring = { version = "0.16", optional = true } -k256 = { version = "0.11", optional = true, features = ["ecdsa"] } -p256 = { version = "0.11", optional = true, features = ["ecdsa"] } +k256 = { version = "0.13.1", optional = true, features = ["ecdsa"] } +p256 = { version = "0.13.2", 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 } -ed25519-dalek = { version = "1", optional = true } +ed25519-dalek = { version = "2.0.0", optional = true } ripemd160 = { version = "0.9", optional = true } bbs = { version = "=0.4.1", optional = true } pairing-plus = { version = "=0.19.0", optional = true } diff --git a/ssi-jwk/Cargo.toml b/ssi-jwk/Cargo.toml index 34b4a6953..6b30ceb98 100644 --- a/ssi-jwk/Cargo.toml +++ b/ssi-jwk/Cargo.toml @@ -11,22 +11,31 @@ documentation = "https://docs.rs/ssi-jwk/" [features] default = ["secp256k1", "secp256r1", "ed25519", "rsa", "eip", "ripemd-160"] ## enable secp256k1 keys -secp256k1 = ["k256", "rand", "k256/keccak256", "ssi-crypto/secp256k1"] +secp256k1 = ["k256", "rand", "ssi-crypto/secp256k1"] ## enable secp256r1 (p256) keys secp256r1 = ["p256", "rand"] ## enable secp384r1 (p384) keys secp384r1 = ["p384", "rand"] ## enable ed25519 (EdDSA) keys -ed25519 = ["ed25519-dalek", "rand_old", "getrandom"] +ed25519 = ["ed25519-dalek", "rand", "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"] +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", "secp256k1"] ## enable ethereum style key hashing -eip = ["ssi-crypto/keccak", "k256/keccak256", "secp256k1"] +eip = ["ssi-crypto/keccak", "secp256k1"] ## enable tezos style key hashing tezos = ["blake2b_simd", "secp256k1", "secp256r1", "bs58"] @@ -39,21 +48,20 @@ 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.11", optional = true, features = ["ecdsa"] } -p256 = { version = "0.11", optional = true, features = ["ecdsa"] } -p384 = { version = "0.11", optional = true, features = ["ecdsa"] } +ssi-crypto = { path = "../ssi-crypto", version = "0.1" } +k256 = { version = "0.13.1", optional = true, features = ["ecdsa"] } +p256 = { version = "0.13.2", optional = true, features = ["ecdsa"] } +p384 = { version = "0.13.0", optional = true, features = ["ecdsa"] } ring = { version = "0.16", 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 } +ed25519-dalek = { version = "2.0.0", optional = true, features = ["rand_core"] } lazy_static = "1.4" bs58 = { version = "0.4", features = ["check"], optional = true } blake2 = { version = "0.9", optional = true } snarkvm-dpc = { version = "0.7.9", optional = true } -snarkvm-algorithms = { version= "0.7.9", optional = true } -snarkvm-curves = { version= "0.7.9", optional = true } +snarkvm-algorithms = { version = "0.7.9", optional = true } +snarkvm-curves = { version = "0.7.9", optional = true } snarkvm-utilities = { version = "0.7.9", optional = true } snarkvm-parameters = { version = "0.7.9", optional = true } blake2b_simd = { version = "0.5", optional = true } diff --git a/ssi-jwk/src/lib.rs b/ssi-jwk/src/lib.rs index 35520bc5c..5490efe80 100644 --- a/ssi-jwk/src/lib.rs +++ b/ssi-jwk/src/lib.rs @@ -269,7 +269,7 @@ impl Default for Algorithm { } impl JWK { - #[cfg(any(feature = "ed25519"))] + #[cfg(feature = "ed25519")] pub fn generate_ed25519() -> Result { #[cfg(feature = "ring")] { @@ -289,12 +289,13 @@ impl JWK { } #[cfg(not(feature = "ring"))] { - let mut csprng = rand_old::rngs::OsRng {}; - let keypair = ed25519_dalek::Keypair::generate(&mut csprng); + let mut csprng = rand::rngs::OsRng {}; + let secret = ed25519_dalek::SigningKey::generate(&mut csprng); + let public = secret.verifying_key(); Ok(JWK::from(Params::OKP(OctetParams { curve: "Ed25519".to_string(), - public_key: Base64urlUInt(keypair.public.as_ref().to_vec()), - private_key: Some(Base64urlUInt(keypair.secret.as_ref().to_vec())), + public_key: Base64urlUInt(public.as_ref().to_vec()), + private_key: Some(Base64urlUInt(secret.to_bytes().to_vec())), }))) } } @@ -303,7 +304,7 @@ impl JWK { pub fn generate_secp256k1() -> Result { let mut rng = rand::rngs::OsRng {}; let secret_key = k256::SecretKey::random(&mut rng); - let sk_bytes = zeroize::Zeroizing::new(secret_key.to_be_bytes().to_vec()); + let sk_bytes = zeroize::Zeroizing::new(secret_key.to_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())); @@ -314,7 +315,7 @@ impl JWK { pub fn generate_p256() -> Result { let mut rng = rand::rngs::OsRng {}; let secret_key = p256::SecretKey::random(&mut rng); - let sk_bytes = zeroize::Zeroizing::new(secret_key.to_be_bytes().to_vec()); + let sk_bytes = zeroize::Zeroizing::new(secret_key.to_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())); @@ -325,7 +326,7 @@ impl JWK { pub fn generate_p384() -> Result { let mut rng = rand::rngs::OsRng {}; let secret_key = p384::SecretKey::random(&mut rng); - let sk_bytes = zeroize::Zeroizing::new(secret_key.to_be_bytes().to_vec()); + let sk_bytes = zeroize::Zeroizing::new(secret_key.to_bytes().to_vec()); let public_key: p384::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())); @@ -492,7 +493,7 @@ impl JWK { } "Multikey" => match multicodec::decode(&pk_bytes) { Ok((codec, pk)) => match codec { - #[cfg(any(feature = "ed25519"))] + #[cfg(feature = "ed25519")] multicodec::Codec::Ed25519Pub => ed25519_parse(&pk), #[cfg(feature = "secp256k1")] multicodec::Codec::Secp256k1Pub => secp256k1_parse(&pk), @@ -512,9 +513,9 @@ impl JWK { let bytes = multibase::decode(multicodec)?.1; match multicodec::decode(&bytes) { Ok((codec, k)) => match codec { - #[cfg(any(feature = "ed25519"))] + #[cfg(feature = "ed25519")] multicodec::Codec::Ed25519Pub => ed25519_parse(&k), - #[cfg(any(feature = "ed25519"))] + #[cfg(feature = "ed25519")] multicodec::Codec::Ed25519Priv => ed25519_parse_private(&k), #[cfg(feature = "secp256k1")] multicodec::Codec::Secp256k1Pub => secp256k1_parse(&k), @@ -793,18 +794,18 @@ impl TryFrom<&RSAParams> for ring::signature::RsaKeyPair { } #[cfg(feature = "ed25519")] -impl TryFrom<&OctetParams> for ed25519_dalek::PublicKey { +impl TryFrom<&OctetParams> for ed25519_dalek::VerifyingKey { type Error = Error; fn try_from(params: &OctetParams) -> Result { if params.curve != *"Ed25519" { return Err(Error::CurveNotImplemented(params.curve.to_string())); } - Ok(Self::from_bytes(¶ms.public_key.0)?) + Ok(params.public_key.0.as_slice().as_ref().try_into()?) } } #[cfg(feature = "ed25519")] -impl TryFrom<&OctetParams> for ed25519_dalek::SecretKey { +impl TryFrom<&OctetParams> for ed25519_dalek::SigningKey { type Error = Error; fn try_from(params: &OctetParams) -> Result { if params.curve != *"Ed25519" { @@ -814,20 +815,7 @@ impl TryFrom<&OctetParams> for ed25519_dalek::SecretKey { .private_key .as_ref() .ok_or(Error::MissingPrivateKey)?; - Ok(Self::from_bytes(&private_key.0)?) - } -} - -#[cfg(feature = "ed25519")] -impl TryFrom<&OctetParams> for ed25519_dalek::Keypair { - type Error = Error; - fn try_from(params: &OctetParams) -> Result { - if params.curve != *"Ed25519" { - return Err(Error::CurveNotImplemented(params.curve.to_string())); - } - let public = ed25519_dalek::PublicKey::try_from(params)?; - let secret = ed25519_dalek::SecretKey::try_from(params)?; - Ok(ed25519_dalek::Keypair { secret, public }) + Ok(private_key.0.as_slice().as_ref().try_into()?) } } @@ -861,7 +849,7 @@ impl TryFrom<&OctetParams> for ring::signature::Ed25519KeyPair { #[cfg(feature = "ed25519")] pub fn ed25519_parse(data: &[u8]) -> Result { - let _ = ed25519_dalek::PublicKey::from_bytes(data)?; + let _: ed25519_dalek::VerifyingKey = data.try_into()?; Ok(JWK::from(Params::OKP(OctetParams { curve: "Ed25519".to_string(), public_key: Base64urlUInt(data.to_owned()), @@ -871,10 +859,10 @@ pub fn ed25519_parse(data: &[u8]) -> Result { #[cfg(feature = "ed25519")] fn ed25519_parse_private(data: &[u8]) -> Result { - let key = ed25519_dalek::SecretKey::from_bytes(data)?; + let key: ed25519_dalek::SigningKey = data.try_into()?; Ok(JWK::from(Params::OKP(OctetParams { curve: "Ed25519".to_string(), - public_key: Base64urlUInt(ed25519_dalek::PublicKey::from(&key).as_bytes().to_vec()), + public_key: Base64urlUInt(ed25519_dalek::VerifyingKey::from(&key).as_bytes().to_vec()), private_key: Some(Base64urlUInt(data.to_owned())), }))) } @@ -932,7 +920,7 @@ pub fn p256_parse(pk_bytes: &[u8]) -> Result { #[cfg(feature = "secp256r1")] fn p256_parse_private(data: &[u8]) -> Result { - let k = p256::SecretKey::from_be_bytes(data)?; + let k = p256::SecretKey::from_bytes(data.into())?; let jwk = JWK { params: Params::EC(ECParams::try_from(&k)?), public_key_use: None, @@ -966,7 +954,7 @@ pub fn p384_parse(pk_bytes: &[u8]) -> Result { #[cfg(feature = "secp384r1")] fn p384_parse_private(data: &[u8]) -> Result { - let k = p384::SecretKey::from_be_bytes(data)?; + let k = p384::SecretKey::from_bytes(data.into())?; let jwk = JWK { params: Params::EC(ECParams::try_from(&k)?), public_key_use: None, @@ -1082,7 +1070,7 @@ impl TryFrom<&ECParams> for k256::SecretKey { .ecc_private_key .as_ref() .ok_or(Error::MissingPrivateKey)?; - let secret_key = k256::SecretKey::from_be_bytes(&private_key.0)?; + let secret_key = k256::SecretKey::from_bytes(private_key.0.as_slice().into())?; Ok(secret_key) } } @@ -1099,7 +1087,7 @@ impl TryFrom<&ECParams> for p256::SecretKey { .ecc_private_key .as_ref() .ok_or(Error::MissingPrivateKey)?; - let secret_key = p256::SecretKey::from_be_bytes(&private_key.0)?; + let secret_key = p256::SecretKey::from_bytes(private_key.0.as_slice().into())?; Ok(secret_key) } } @@ -1116,7 +1104,7 @@ impl TryFrom<&ECParams> for p384::SecretKey { .ecc_private_key .as_ref() .ok_or(Error::MissingPrivateKey)?; - let secret_key = p384::SecretKey::from_be_bytes(&private_key.0)?; + let secret_key = p384::SecretKey::from_bytes(private_key.0.as_slice().into())?; Ok(secret_key) } } @@ -1204,7 +1192,7 @@ impl TryFrom<&k256::SecretKey> for ECParams { curve: Some("secp256k1".to_string()), x_coordinate: Some(Base64urlUInt(x.to_vec())), y_coordinate: Some(Base64urlUInt(y.to_vec())), - ecc_private_key: Some(Base64urlUInt(k.to_be_bytes().to_vec())), + ecc_private_key: Some(Base64urlUInt(k.to_bytes().to_vec())), }) } } @@ -1239,7 +1227,7 @@ impl TryFrom<&p256::SecretKey> for ECParams { curve: Some("P-256".to_string()), x_coordinate: Some(Base64urlUInt(x.to_vec())), y_coordinate: Some(Base64urlUInt(y.to_vec())), - ecc_private_key: Some(Base64urlUInt(k.to_be_bytes().to_vec())), + ecc_private_key: Some(Base64urlUInt(k.to_bytes().to_vec())), }) } } @@ -1274,7 +1262,7 @@ impl TryFrom<&p384::SecretKey> for ECParams { curve: Some("P-384".to_string()), x_coordinate: Some(Base64urlUInt(x.to_vec())), y_coordinate: Some(Base64urlUInt(y.to_vec())), - ecc_private_key: Some(Base64urlUInt(k.to_be_bytes().to_vec())), + ecc_private_key: Some(Base64urlUInt(k.to_bytes().to_vec())), }) } } diff --git a/ssi-jws/Cargo.toml b/ssi-jws/Cargo.toml index 96ac2f759..11217930e 100644 --- a/ssi-jws/Cargo.toml +++ b/ssi-jws/Cargo.toml @@ -9,9 +9,23 @@ repository = "https://github.com/spruceid/ssi/" documentation = "https://docs.rs/ssi-jws/" [features] -default = ["secp256k1", "secp256r1", "ed25519", "rsa", "eip", "ssi-jwk/ripemd-160"] +default = [ + "secp256k1", + "secp256r1", + "ed25519", + "rsa", + "eip", + "ssi-jwk/ripemd-160", +] ## enable secp256k1 signatures -secp256k1 = ["ssi-jwk/secp256k1", "k256/keccak256", "ssi-crypto/secp256k1", "blake2", "dep:sha2"] +secp256k1 = [ + "ssi-jwk/secp256k1", + "k256", + "ssi-crypto/secp256k1", + "blake2", + "dep:sha2", + "dep:sha3", +] ## enable secp256r1 (p256) signatures secp256r1 = ["ssi-jwk/secp256r1", "p256", "blake2"] ## enable secp384r1 (p384) signatures @@ -24,7 +38,7 @@ 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", "secp256k1"] +eip = ["ssi-jwk/eip", "ssi-crypto/keccak", "secp256k1"] ## enable tezos style signatures tezos = ["ssi-jwk/tezos", "secp256k1", "secp256r1", "ed25519"] @@ -36,18 +50,19 @@ thiserror = "1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" base64 = "0.12" -k256 = { version = "0.11", optional = true, features = ["ecdsa"] } -p256 = { version = "0.11", optional = true, features = ["ecdsa"] } -p384 = { version = "0.11", optional = true, features = ["ecdsa"] } +k256 = { version = "0.13.1", optional = true, features = ["ecdsa"] } +p256 = { version = "0.13.2", optional = true, features = ["ecdsa"] } +p384 = { version = "0.13.0", optional = true, features = ["ecdsa"] } # blake2b_simd = { version = "0.5", optional = true } blake2 = { version = "0.10", optional = true } -ed25519-dalek = { version = "1", optional = true } +ed25519-dalek = { version = "2.0.0", optional = true } sha2 = { version = "0.10", optional = true } +sha3 = { version = "0.10.8", optional = true } rsa = { version = "0.6", optional = true } rand = { version = "0.8", optional = true } ring = { version = "0.16", optional = true } -ssi-crypto = { path = "../ssi-crypto", version = "0.1"} -ssi-jwk = { path = "../ssi-jwk", version = "0.1"} +ssi-crypto = { path = "../ssi-crypto", version = "0.1" } +ssi-jwk = { path = "../ssi-jwk", version = "0.1" } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] diff --git a/ssi-jws/src/lib.rs b/ssi-jws/src/lib.rs index 628459295..b4e14f73b 100644 --- a/ssi-jws/src/lib.rs +++ b/ssi-jws/src/lib.rs @@ -123,7 +123,7 @@ pub fn sign_bytes(algorithm: Algorithm, data: &[u8], key: &JWK) -> Result as Digest>::new_with_prefix(data) + Algorithm::EdBlake2b => blake2::Blake2b::::new_with_prefix(data) .finalize() .to_vec(), _ => data.to_vec(), @@ -136,95 +136,109 @@ pub fn sign_bytes(algorithm: Algorithm, data: &[u8], key: &JWK) -> Result { - match algorithm { - #[cfg(feature = "p384")] - Algorithm::ES384 => { - use p384::ecdsa::signature::{Signature, Signer}; - let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; - let secret_key = p384::SecretKey::try_from(ec)?; - let signing_key = p384::ecdsa::SigningKey::from(secret_key); - let sig: p384::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)?; - 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)?; - 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(Error::MissingCurve)?; - 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_digest(::new_with_prefix(data))?; - 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)?; - 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 => { - use p256::ecdsa::signature::{ + JWKParams::EC(ec) => match algorithm { + #[cfg(feature = "p384")] + Algorithm::ES384 => { + use p384::ecdsa::{signature::Signer, Signature}; + let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; + let secret_key = p384::SecretKey::try_from(ec)?; + let signing_key = p384::ecdsa::SigningKey::from(secret_key); + let sig: p384::ecdsa::Signature = + signing_key.try_sign(data).map_err(ssi_jwk::Error::from)?; + sig.to_bytes().to_vec() + } + #[cfg(feature = "p256")] + Algorithm::ES256 => { + use p256::ecdsa::{signature::Signer, Signature}; + let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; + 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.to_bytes().to_vec() + } + #[cfg(feature = "secp256k1")] + Algorithm::ES256K => { + use k256::ecdsa::{signature::Signer, Signature}; + let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; + let secret_key = k256::SecretKey::try_from(ec)?; + let signing_key = k256::ecdsa::SigningKey::from(secret_key); + let sig: Signature = signing_key.try_sign(data).map_err(ssi_jwk::Error::from)?; + sig.to_bytes().to_vec() + } + #[cfg(feature = "secp256k1")] + Algorithm::ES256KR => { + use k256::ecdsa::{ + signature::{digest::Digest, Signer}, + Signature, + }; + let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?; + let secret_key = k256::SecretKey::try_from(ec)?; + let signing_key = k256::ecdsa::SigningKey::from(secret_key); + let (sig, rec_id) = + signing_key.sign_digest_recoverable(sha2::Sha256::new_with_prefix(data))?; + let mut res = sig.to_bytes().to_vec(); + res.push(rec_id.to_byte()); + res + } + #[cfg(feature = "secp256k1")] + Algorithm::ESKeccakKR => { + use k256::ecdsa::{ + signature::{digest::Digest, Signer}, + Signature, + }; + let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; + let secret_key = k256::SecretKey::try_from(ec)?; + let signing_key = k256::ecdsa::SigningKey::from(secret_key); + let (sig, rec_id) = signing_key + .sign_digest_recoverable(sha3::Keccak256::new_with_prefix(data)) + .map_err(ssi_jwk::Error::from)?; + let mut res = sig.to_bytes().to_vec(); + res.push(rec_id.to_byte()); + res + } + #[cfg(feature = "p256")] + Algorithm::ESBlake2b => { + use p256::ecdsa::{ + signature::{ digest::{consts::U32, Digest}, - DigestSigner, Signature, - }; - let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?; - 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() - } - #[cfg(feature = "secp256k1")] - Algorithm::ESBlake2bK => { - use k256::ecdsa::signature::{ + DigestSigner, + }, + Signature, + }; + let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?; + 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(blake2::Blake2b::::new_with_prefix(data))?; + sig.to_bytes().to_vec() + } + #[cfg(feature = "secp256k1")] + Algorithm::ESBlake2bK => { + use k256::ecdsa::{ + signature::{ digest::{consts::U32, Digest}, - DigestSigner, Signature, - }; - let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?; - 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() - } - _ => { - return Err(Error::UnsupportedAlgorithm); - } + DigestSigner, + }, + Signature, + }; + let curve = ec.curve.as_ref().ok_or(Error::MissingCurve)?; + 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(blake2::Blake2b::::new_with_prefix(data))?; + sig.to_bytes().to_vec() } - } + _ => { + return Err(Error::UnsupportedAlgorithm); + } + }, _ => return Err(Error::JWK(ssi_jwk::Error::KeyTypeNotImplemented)), }; clear_on_drop::clear_stack(1); @@ -316,9 +330,9 @@ pub fn verify_bytes_warnable( #[cfg(feature = "ed25519")] { use ed25519_dalek::Verifier; - let public_key = ed25519_dalek::PublicKey::try_from(okp)?; - let signature = ed25519_dalek::Signature::from_bytes(signature) - .map_err(ssi_jwk::Error::from)?; + let public_key = ed25519_dalek::VerifyingKey::try_from(okp)?; + let signature: ed25519_dalek::Signature = + signature.try_into().map_err(ssi_jwk::Error::from)?; public_key .verify(&hash, &signature) .map_err(ssi_jwk::Error::from)?; @@ -348,7 +362,8 @@ pub fn verify_bytes_warnable( k256::ecdsa::Signature::try_from(signature).map_err(ssi_jwk::Error::from)?; let normalized_sig = if let Some(s) = sig.normalize_s() { // For user convenience, output the normalized signature. - let sig_normalized_b64 = base64::encode_config(s, base64::URL_SAFE_NO_PAD); + let sig_normalized_b64 = + base64::encode_config(s.to_bytes(), base64::URL_SAFE_NO_PAD); warnings.push(format!( "Non-normalized ES256K signature. Normalized: {sig_normalized_b64}" )); @@ -362,41 +377,79 @@ pub fn verify_bytes_warnable( } #[cfg(feature = "secp256k1")] Algorithm::ES256KR => { - use k256::ecdsa::signature::{ - digest::{consts::U32, Digest}, - DigestVerifier, Verifier, + use k256::ecdsa::{ + signature::{ + digest::{consts::U32, Digest}, + DigestVerifier, Verifier, + }, + RecoveryId, VerifyingKey, }; + if signature.len() != 65 { + Err(k256::ecdsa::Error::new())?; + } let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; let public_key = k256::PublicKey::try_from(ec)?; let verifying_key = k256::ecdsa::VerifyingKey::from(public_key); - let sig = k256::ecdsa::recoverable::Signature::try_from(signature) + let sig = k256::ecdsa::Signature::try_from(&signature[..64]) .map_err(ssi_jwk::Error::from)?; - 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 - .push("Signature uses legacy mode ES256K-R with Keccak-256".to_string()); + let rec_id = k256::ecdsa::RecoveryId::try_from(signature[64]) + .map_err(ssi_jwk::Error::from)?; + match VerifyingKey::recover_from_digest( + ::new_with_prefix(data), + &sig, + rec_id, + ) { + Err(_e) => { + // Legacy mode: allow using Keccak-256 instead of SHA-256 + verify_bytes(Algorithm::ESKeccakKR, data, key, signature)?; + warnings.push( + "Signature uses legacy mode ES256K-R with Keccak-256".to_string(), + ); + } + Ok(recovered_key) => match recovered_key == verifying_key { + true => (), + false => Err(k256::ecdsa::Error::new())?, + }, } } #[cfg(feature = "eip")] Algorithm::ESKeccakKR => { - use k256::ecdsa::signature::Verifier; + use k256::ecdsa::{ + signature::{ + digest::{consts::U32, Digest}, + DigestVerifier, Verifier, + }, + RecoveryId, VerifyingKey, + }; + if signature.len() != 65 { + Err(k256::ecdsa::Error::new())?; + } let curve = ec.curve.as_ref().ok_or(ssi_jwk::Error::MissingCurve)?; let public_key = k256::PublicKey::try_from(ec)?; let verifying_key = k256::ecdsa::VerifyingKey::from(public_key); - let sig = k256::ecdsa::recoverable::Signature::try_from(signature) + let sig = k256::ecdsa::Signature::try_from(&signature[..64]) .map_err(ssi_jwk::Error::from)?; - verifying_key - .verify(data, &sig) + let rec_id = k256::ecdsa::RecoveryId::try_from(signature[64]) .map_err(ssi_jwk::Error::from)?; + let recovered_key = VerifyingKey::recover_from_digest( + sha3::Keccak256::new_with_prefix(data), + &sig, + rec_id, + ) + .map_err(ssi_jwk::Error::from)?; + match recovered_key == verifying_key { + true => (), + false => Err(k256::ecdsa::Error::new())?, + } } #[cfg(feature = "p256")] Algorithm::ESBlake2b => { - use p256::ecdsa::signature::{ - digest::{consts::U32, 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)?; let public_key = p256::PublicKey::try_from(ec)?; @@ -465,17 +518,22 @@ 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)?; + use k256::ecdsa::VerifyingKey; + if signature.len() != 65 { + Err(k256::ecdsa::Error::new())?; + } + let sig = + k256::ecdsa::Signature::try_from(&signature[..64]).map_err(ssi_jwk::Error::from)?; + let rec_id = + k256::ecdsa::RecoveryId::try_from(signature[64]).map_err(ssi_jwk::Error::from)?; let hash = ssi_crypto::hashes::sha256::sha256(data); let digest = k256::elliptic_curve::FieldBytes::::from_slice(&hash); - let recovered_key = sig - .recover_verifying_key_from_digest_bytes(digest) + let recovered_key = VerifyingKey::recover_from_prehash(digest, &sig, rec_id) .map_err(ssi_jwk::Error::from)?; use ssi_jwk::ECParams; let jwk = JWK { params: JWKParams::EC(ECParams::try_from( - &k256::PublicKey::from_sec1_bytes(&recovered_key.to_bytes()) + &k256::PublicKey::from_sec1_bytes(&recovered_key.to_sec1_bytes()) .map_err(ssi_jwk::Error::from)?, )?), public_key_use: None, @@ -491,14 +549,23 @@ 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_verifying_key(data) - .map_err(ssi_jwk::Error::from)?; + use k256::ecdsa::{signature::digest::Digest, VerifyingKey}; + if signature.len() != 65 { + Err(k256::ecdsa::Error::new())?; + } + let sig = + k256::ecdsa::Signature::try_from(&signature[..64]).map_err(ssi_jwk::Error::from)?; + let rec_id = + k256::ecdsa::RecoveryId::try_from(signature[64]).map_err(ssi_jwk::Error::from)?; + let recovered_key = VerifyingKey::recover_from_digest( + sha3::Keccak256::new_with_prefix(data), + &sig, + rec_id, + ) + .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()) + &k256::PublicKey::from_sec1_bytes(&recovered_key.to_sec1_bytes()) .map_err(ssi_jwk::Error::from)?, )?)); Ok(jwk) diff --git a/ssi-ldp/Cargo.toml b/ssi-ldp/Cargo.toml index 865c8e617..28ad56b34 100644 --- a/ssi-ldp/Cargo.toml +++ b/ssi-ldp/Cargo.toml @@ -18,9 +18,15 @@ secp384r1 = ["ssi-jws/secp384r1"] ed25519 = ["ssi-jws/ed25519"] rsa = ["ssi-jws/rsa"] ## enable the EIP-defined LDPs: EIP712 -eip = ["keccak-hash", "ssi-caips/eip", "secp256k1", "ssi-jws/eip"] +eip = ["keccak-hash", "ssi-caips/eip", "secp256k1", "ssi-jws/eip", "sha3"] ## enable LDPs from the Tezos Ecosystem -tezos = ["ssi-tzkey", "ssi-jws/tezos", "ssi-caips/tezos", "secp256k1", "secp256r1"] +tezos = [ + "ssi-tzkey", + "ssi-jws/tezos", + "ssi-caips/tezos", + "secp256k1", + "secp256r1", +] ## enable LDPs from the Aleo Ecosystem aleo = ["ssi-jws/aleo", "ssi-caips/aleo"] ## enable LDPs from the Solana Ecosystem @@ -46,16 +52,17 @@ serde_jcs = "0.1" hex = "0.4" multibase = "0.8" sha2 = "0.10.7" -k256 = { version = "0.11", optional = true, features = ["ecdsa"] } -p256 = { version = "0.11", optional = true, features = ["ecdsa"] } +sha3 = { version = "0.10.8", optional = true } +k256 = { version = "0.13.1", optional = true, features = ["ecdsa"] } +p256 = { version = "0.13.2", optional = true, features = ["ecdsa"] } keccak-hash = { version = "0.7", optional = true } -ssi-jwk = { path = "../ssi-jwk", version = "0.1.1"} -ssi-json-ld = { path = "../ssi-json-ld", version = "0.2"} -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-tzkey = { path = "../ssi-tzkey", version = "0.1", optional = true} +ssi-jwk = { path = "../ssi-jwk", version = "0.1.1" } +ssi-json-ld = { path = "../ssi-json-ld", version = "0.2" } +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-tzkey = { path = "../ssi-tzkey", version = "0.1", optional = true } ssi-caips = { path = "../ssi-caips", version = "0.1" } ssi-contexts = { version = "0.1.5", path = "../contexts" } diff --git a/ssi-ldp/src/eip712.rs b/ssi-ldp/src/eip712.rs index 7a5fd18e0..de1a71c28 100644 --- a/ssi-ldp/src/eip712.rs +++ b/ssi-ldp/src/eip712.rs @@ -1615,7 +1615,7 @@ mod tests { let sk_bytes = bytes_from_hex(sk_hex).unwrap(); use ssi_jwk::{Base64urlUInt, ECParams, Params, JWK}; - let sk = k256::SecretKey::from_be_bytes(&sk_bytes).unwrap(); + let sk = k256::SecretKey::from_bytes(sk_bytes.as_slice().into()).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 628947f5a..93ef5e515 100644 --- a/ssi-ldp/src/suites/eip.rs +++ b/ssi-ldp/src/suites/eip.rs @@ -1,5 +1,6 @@ use super::super::*; use crate::eip712::TypedData; +use k256::ecdsa::VerifyingKey; use serde_json::Value; use ssi_dids::did_resolve::{resolve_vm, DIDResolver}; use ssi_json_ld::ContextLoader; @@ -15,7 +16,6 @@ impl Eip712Signature2021 { key: &JWK, extra_proof_properties: Option>, ) -> Result { - use k256::ecdsa::signature::Signer; let mut proof = Proof { context: serde_json::json!([EIP712VM_CONTEXT.clone()]), ..Proof::new(ProofSuiteType::Eip712Signature2021) @@ -31,11 +31,12 @@ impl Eip712Signature2021 { }; let secret_key = k256::SecretKey::try_from(ec_params)?; let signing_key = k256::ecdsa::SigningKey::from(secret_key); - let sig: k256::ecdsa::recoverable::Signature = - signing_key.try_sign(&bytes).map_err(ssi_jwk::Error::from)?; - let sig_bytes = &mut sig.as_ref().to_vec(); + let (sig, rec_id) = signing_key + .sign_digest_recoverable(sha3::Keccak256::new_with_prefix(bytes)) + .map_err(ssi_jwk::Error::from)?; + let sig_bytes = &mut sig.to_vec(); // Recovery ID starts at 27 instead of 0. - sig_bytes[64] += 27; + sig_bytes.push(rec_id.to_byte() + 27); let sig_hex = ssi_crypto::hashes::keccak::bytes_to_lowerhex(sig_bytes); proof.proof_value = Some(sig_hex); Ok(proof) @@ -90,18 +91,18 @@ impl Eip712Signature2021 { return Err(Error::HexString); } let dec_sig = hex::decode(&sig_hex[2..])?; + let rec_id = + k256::ecdsa::RecoveryId::try_from(dec_sig[64] % 27).map_err(ssi_jwk::Error::from)?; let sig = k256::ecdsa::Signature::try_from(&dec_sig[..64]).map_err(ssi_jwk::Error::from)?; - let rec_id = k256::ecdsa::recoverable::Id::try_from(dec_sig[64] % 27) - .map_err(ssi_jwk::Error::from)?; - let sig = - 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_verifying_key(&bytes) - .map_err(ssi_jwk::Error::from)?; + let recovered_key = VerifyingKey::recover_from_digest( + sha3::Keccak256::new_with_prefix(bytes), + &sig, + rec_id, + ) + .map_err(ssi_jwk::Error::from)?; let jwk = JWK { params: JWKParams::EC(ECParams::try_from( - &k256::PublicKey::from_sec1_bytes(&recovered_key.to_bytes()) + &k256::PublicKey::from_sec1_bytes(&recovered_key.to_sec1_bytes()) .map_err(ssi_jwk::Error::from)?, )?), public_key_use: None, @@ -126,7 +127,6 @@ impl EthereumEip712Signature2021 { key: &JWK, extra_proof_properties: Option>, ) -> Result { - use k256::ecdsa::signature::Signer; // TODO: conform to spec: no domain let mut props = extra_proof_properties.clone(); if let Some(ref eip712_domain) = options.eip712_domain { @@ -149,11 +149,12 @@ impl EthereumEip712Signature2021 { }; let secret_key = k256::SecretKey::try_from(ec_params)?; let signing_key = k256::ecdsa::SigningKey::from(secret_key); - let sig: k256::ecdsa::recoverable::Signature = - signing_key.try_sign(&bytes).map_err(ssi_jwk::Error::from)?; - let sig_bytes = &mut sig.as_ref().to_vec(); + let (sig, rec_id) = signing_key + .sign_digest_recoverable(sha3::Keccak256::new_with_prefix(bytes)) + .map_err(ssi_jwk::Error::from)?; + let sig_bytes = &mut sig.to_vec(); // Recovery ID starts at 27 instead of 0. - sig_bytes[64] += 27; + sig_bytes.push(rec_id.to_byte() + 27); let sig_hex = ssi_crypto::hashes::keccak::bytes_to_lowerhex(sig_bytes); proof.proof_value = Some(sig_hex); Ok(proof) @@ -208,19 +209,20 @@ impl EthereumEip712Signature2021 { return Err(Error::HexString); } let dec_sig = hex::decode(&sig_hex[2..])?; - let rec_id = k256::ecdsa::recoverable::Id::try_from(dec_sig[64] % 27) - .map_err(ssi_jwk::Error::from)?; + let rec_id = + k256::ecdsa::RecoveryId::try_from(dec_sig[64] % 27).map_err(ssi_jwk::Error::from)?; let sig = k256::ecdsa::Signature::try_from(&dec_sig[..64]).map_err(ssi_jwk::Error::from)?; - let sig = - k256::ecdsa::recoverable::Signature::new(&sig, rec_id).map_err(ssi_jwk::Error::from)?; let typed_data = TypedData::from_document_and_options_json(document, proof).await?; let bytes = typed_data.bytes()?; - let recovered_key = sig - .recover_verifying_key(&bytes) - .map_err(ssi_jwk::Error::from)?; + let recovered_key = VerifyingKey::recover_from_digest( + sha3::Keccak256::new_with_prefix(bytes), + &sig, + rec_id, + ) + .map_err(ssi_jwk::Error::from)?; let jwk = JWK { params: JWKParams::EC(ECParams::try_from( - &k256::PublicKey::from_sec1_bytes(&recovered_key.to_bytes()) + &k256::PublicKey::from_sec1_bytes(&recovered_key.to_sec1_bytes()) .map_err(ssi_jwk::Error::from)?, )?), public_key_use: None, @@ -246,7 +248,6 @@ impl EthereumPersonalSignature2021 { key: &JWK, extra_proof_properties: Option>, ) -> Result { - use k256::ecdsa::signature::Signer; let mut proof = Proof { context: serde_json::json!([EPSIG_CONTEXT.clone()]), ..Proof::new(ProofSuiteType::EthereumPersonalSignature2021) @@ -262,11 +263,12 @@ impl EthereumPersonalSignature2021 { }; let secret_key = k256::SecretKey::try_from(ec_params)?; let signing_key = k256::ecdsa::SigningKey::from(secret_key); - let sig: k256::ecdsa::recoverable::Signature = - signing_key.try_sign(&hash).map_err(ssi_jwk::Error::from)?; - let sig_bytes = &mut sig.as_ref().to_vec(); + let (sig, rec_id) = signing_key + .sign_digest_recoverable(sha3::Keccak256::new_with_prefix(hash)) + .map_err(ssi_jwk::Error::from)?; + let sig_bytes = &mut sig.to_vec(); // Recovery ID starts at 27 instead of 0. - sig_bytes[64] += 27; + sig_bytes.push(rec_id.to_byte() + 27); let sig_hex = ssi_crypto::hashes::keccak::bytes_to_lowerhex(sig_bytes); proof.proof_value = Some(sig_hex); Ok(proof) @@ -319,20 +321,18 @@ impl EthereumPersonalSignature2021 { return Err(Error::HexString); } let dec_sig = hex::decode(&sig_hex[2..])?; - let rec_id = k256::ecdsa::recoverable::Id::try_from(dec_sig[64] % 27) - .map_err(ssi_jwk::Error::from)?; + let rec_id = + k256::ecdsa::RecoveryId::try_from(dec_sig[64] % 27).map_err(ssi_jwk::Error::from)?; let sig = k256::ecdsa::Signature::try_from(&dec_sig[..64]).map_err(ssi_jwk::Error::from)?; - let sig = - k256::ecdsa::recoverable::Signature::new(&sig, rec_id).map_err(ssi_jwk::Error::from)?; let signing_string = 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_verifying_key(&hash) - .map_err(ssi_jwk::Error::from)?; + let recovered_key = + VerifyingKey::recover_from_digest(sha3::Keccak256::new_with_prefix(hash), &sig, rec_id) + .map_err(ssi_jwk::Error::from)?; let jwk = JWK { params: JWKParams::EC(ECParams::try_from( - &k256::PublicKey::from_sec1_bytes(&recovered_key.to_bytes()) + &k256::PublicKey::from_sec1_bytes(&recovered_key.to_sec1_bytes()) .map_err(ssi_jwk::Error::from)?, )?), public_key_use: None, diff --git a/ssi-tzkey/Cargo.toml b/ssi-tzkey/Cargo.toml index b177d706c..0dfd7c391 100644 --- a/ssi-tzkey/Cargo.toml +++ b/ssi-tzkey/Cargo.toml @@ -9,9 +9,13 @@ repository = "https://github.com/spruceid/ssi/" documentation = "https://docs.rs/ssi-tzkey/" [dependencies] -ssi-jwk = { path = "../ssi-jwk", version = "0.1", default-features = false, features = ["tezos"]} -ssi-jws = { path = "../ssi-jws", version = "0.1", default-features = false, features = ["tezos"] } -ed25519-dalek = "1.0.1" +ssi-jwk = { path = "../ssi-jwk", version = "0.1", default-features = false, features = [ + "tezos", +] } +ssi-jws = { path = "../ssi-jws", version = "0.1", default-features = false, features = [ + "tezos", +] } +ed25519-dalek = "2.0.0" thiserror = "1.0" bs58 = { version = "0.4", features = ["check"] } diff --git a/ssi-tzkey/src/lib.rs b/ssi-tzkey/src/lib.rs index f36dce099..6ddc4a177 100644 --- a/ssi-tzkey/src/lib.rs +++ b/ssi-tzkey/src/lib.rs @@ -77,13 +77,9 @@ pub fn jwk_from_tezos_key(tz_pk: &str) -> Result { let sk_bytes = bs58::decode(&tz_pk).with_check(None).into_vec()?[4..].to_owned(); let pk_bytes; { - let sk = ed25519_dalek::SecretKey::from_bytes(if sk_bytes.len() == 64 { - &sk_bytes[..32] - } else { - &sk_bytes - }) - .map_err(ssi_jwk::Error::from)?; - pk_bytes = ed25519_dalek::PublicKey::from(&sk).as_bytes().to_vec() + let sk = ed25519_dalek::SigningKey::try_from(sk_bytes.as_slice()) + .map_err(ssi_jwk::Error::from)?; + pk_bytes = ed25519_dalek::VerifyingKey::from(&sk).as_bytes().to_vec() } ( Algorithm::EdBlake2b, diff --git a/ssi-vc/Cargo.toml b/ssi-vc/Cargo.toml index fb9db22e0..89b600468 100644 --- a/ssi-vc/Cargo.toml +++ b/ssi-vc/Cargo.toml @@ -16,11 +16,19 @@ thiserror = "1.0" flate2 = "1.0" bitvec = "0.20" base64 = "0.12" -reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] } +reqwest = { version = "0.11", default-features = false, features = [ + "json", + "rustls-tls", +] } cacaos = { version = "0.5.1" } siwe-recap = { version = "0.1" } -libipld = { version = "0.14", default-features = false, features = ["dag-cbor", "derive"]} -multihash = { version = "0.16", default-features = false, features = ["blake3"] } +libipld = { version = "0.14", default-features = false, features = [ + "dag-cbor", + "derive", +] } +multihash = { version = "0.16", default-features = false, features = [ + "blake3", +] } iref = "2.2.2" ssi-jwt = { path = "../ssi-jwt", version = "0.1", default-features = false } ssi-jws = { path = "../ssi-jws", version = "0.1", default-features = false } @@ -40,11 +48,16 @@ chrono = { version = "0.4", features = ["serde", "wasmbind"] } async-std = { version = "1.9", features = ["attributes"] } multibase = "0.8" hex = "0.4" -k256 = { version = "0.11", features = ["ecdsa"] } +sha3 = "0.10.8" +k256 = { version = "0.13.1", features = ["ecdsa"] } keccak-hash = { version = "0.7" } serde_jcs = "0.1" ssi-crypto = { path = "../ssi-crypto" } -ssi-ldp = { path = "../ssi-ldp", features = ["aleo", "example-http-issuer", "secp384r1"] } +ssi-ldp = { path = "../ssi-ldp", features = [ + "aleo", + "example-http-issuer", + "secp384r1", +] } ssi-dids = { path = "../ssi-dids", version = "0.1", features = ["example"] } josekit = "0.8.2" time = "0.3.20" diff --git a/ssi-vc/src/cacao.rs b/ssi-vc/src/cacao.rs index 4cc15b354..af6e325ce 100644 --- a/ssi-vc/src/cacao.rs +++ b/ssi-vc/src/cacao.rs @@ -118,6 +118,8 @@ pub(crate) mod tests { use ssi_dids::example::DIDExample; use ssi_jwk::JWK; + use sha3::Digest; + const VC_ID_1: &str = "http://example.edu/credentials/1872"; const VC_ID_2: &str = "http://example.edu/credentials/0000"; const VP_ID: &str = "uuid:my_vp"; @@ -137,7 +139,7 @@ pub(crate) mod tests { credential: Option<(&str, (&str, &str, &JWK))>, ) -> Vec { use cacaos::{siwe, siwe_cacao::SiweCacao}; - use k256::{ecdsa::signature::Signer, elliptic_curve::sec1::ToEncodedPoint}; + use k256::elliptic_curve::sec1::ToEncodedPoint; use keccak_hash::keccak; use libipld::{cbor::DagCborCodec, multihash::Code, store::DefaultParams, Block}; use siwe_recap::{Builder, Namespace}; @@ -217,11 +219,14 @@ pub(crate) mod tests { None }; - let hash = + let data = ssi_crypto::hashes::keccak::prefix_personal_message(&delegation_message.to_string()); - let sig: k256::ecdsa::recoverable::Signature = signing_key.try_sign(&hash).unwrap(); - let mut delegation_sig = sig.as_ref().to_vec(); - delegation_sig[64] += 27; + let (sig, rec_id) = signing_key + .sign_digest_recoverable(sha3::Keccak256::new_with_prefix(data)) + .unwrap(); + let mut delegation_sig = sig.to_vec(); + // Recovery ID starts at 27 instead of 0. + delegation_sig.push(rec_id.to_byte() + 27); let delegation_cacao = SiweCacao::new( delegation_message.try_into().unwrap(), diff --git a/ssi-vc/src/lib.rs b/ssi-vc/src/lib.rs index e3410312b..c5f520485 100644 --- a/ssi-vc/src/lib.rs +++ b/ssi-vc/src/lib.rs @@ -3572,6 +3572,7 @@ _:c14n0 ec, _ => unreachable!(), }; - use k256::ecdsa::signature::Signer; let secret_key = k256::SecretKey::try_from(ec_params).unwrap(); let signing_key = k256::ecdsa::SigningKey::from(secret_key); - let sig: k256::ecdsa::recoverable::Signature = signing_key.try_sign(&bytes).unwrap(); - let sig_bytes = &mut sig.as_ref().to_vec(); + let (sig, rec_id) = signing_key + .sign_digest_recoverable(sha3::Keccak256::new_with_prefix(bytes)) + .unwrap(); + let sig_bytes = &mut sig.to_vec(); // Recovery ID starts at 27 instead of 0. - sig_bytes[64] += 27; + sig_bytes.push(rec_id.to_byte() + 27); let sig_hex = ssi_crypto::hashes::keccak::bytes_to_lowerhex(sig_bytes); let mut proof = proof.clone(); proof.proof_value = Some(sig_hex.clone());