RUSTSEC-2021-0076 bump libsecp256k1 (#9391)

* RUSTSEC-2021-0076 bump libsecp256k1

libsecp256k1 allows overflowing signatures
https://rustsec.org/advisories/RUSTSEC-2021-0076

Changes were made to conform to libsecp256k1 version differences.

Closes #9356

* parse_standard_slice() -> parse_overflowing_slice()

* Added v2 host function for ecdsa_verify

* Add feature tag over helpers

* Added ecdsa_verify v2 to test runner

* PR feedback

- Spaces -> tabs
- renamed two helper functions

* Fixed imports after rebasing

* Bump rest of libsecp256k1 (and libp2p)

libp2p also uses libsecp256k1 so it is required to be bumped too, along
with all the version difference changes.

* Add version2 for ecdsa pubkey recovery

* libp2p rebase master fixes

* Fix test panic when non Behaviour event is returned

* Update bin/node/browser-testing/Cargo.toml

* Update primitives/core/src/ecdsa.rs

* Update primitives/core/src/ecdsa.rs

* Update Cargo.lock

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
Trevor Arjeski
2021-08-16 17:17:10 +03:00
committed by GitHub
parent 65a8b00f3b
commit d9f02296ab
26 changed files with 583 additions and 367 deletions
+61 -39
View File
@@ -19,10 +19,8 @@
//! Simple ECDSA API.
// end::description[]
#[cfg(feature = "full_crypto")]
use sp_std::vec::Vec;
use codec::{Decode, Encode, MaxEncodedLen};
use sp_runtime_interface::pass_by::PassByInner;
use sp_std::cmp::Ordering;
#[cfg(feature = "std")]
@@ -40,12 +38,11 @@ use bip39::{Language, Mnemonic, MnemonicType};
#[cfg(feature = "full_crypto")]
use core::convert::{TryFrom, TryInto};
#[cfg(feature = "full_crypto")]
use secp256k1::{PublicKey, SecretKey};
use libsecp256k1::{PublicKey, SecretKey};
#[cfg(feature = "std")]
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use sp_runtime_interface::pass_by::PassByInner;
#[cfg(feature = "std")]
use substrate_bip39::seed_from_entropy;
#[cfg(feature = "full_crypto")]
use sp_std::vec::Vec;
/// An identifier used to match public keys against ecdsa keys
pub const CRYPTO_ID: CryptoTypeId = CryptoTypeId(*b"ecds");
@@ -108,7 +105,7 @@ impl Public {
/// This will convert the full public key into the compressed format.
#[cfg(feature = "std")]
pub fn from_full(full: &[u8]) -> Result<Self, ()> {
secp256k1::PublicKey::parse_slice(full, None)
libsecp256k1::PublicKey::parse_slice(full, None)
.map(|k| k.serialize_compressed())
.map(Self)
.map_err(|_| ())
@@ -364,9 +361,9 @@ impl Signature {
/// Recover the public key from this signature and a message.
#[cfg(feature = "full_crypto")]
pub fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<Public> {
let message = secp256k1::Message::parse(&blake2_256(message.as_ref()));
let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref()));
let sig: (_, _) = self.try_into().ok()?;
secp256k1::recover(&message, &sig.0, &sig.1)
libsecp256k1::recover(&message, &sig.0, &sig.1)
.ok()
.map(|recovered| Public(recovered.serialize_compressed()))
}
@@ -374,19 +371,19 @@ impl Signature {
/// Recover the public key from this signature and a pre-hashed message.
#[cfg(feature = "full_crypto")]
pub fn recover_prehashed(&self, message: &[u8; 32]) -> Option<Public> {
let message = secp256k1::Message::parse(message);
let message = libsecp256k1::Message::parse(message);
let sig: (_, _) = self.try_into().ok()?;
secp256k1::recover(&message, &sig.0, &sig.1)
libsecp256k1::recover(&message, &sig.0, &sig.1)
.ok()
.map(|key| Public(key.serialize_compressed()))
}
}
#[cfg(feature = "full_crypto")]
impl From<(secp256k1::Signature, secp256k1::RecoveryId)> for Signature {
fn from(x: (secp256k1::Signature, secp256k1::RecoveryId)) -> Signature {
impl From<(libsecp256k1::Signature, libsecp256k1::RecoveryId)> for Signature {
fn from(x: (libsecp256k1::Signature, libsecp256k1::RecoveryId)) -> Signature {
let mut r = Self::default();
r.0[0..64].copy_from_slice(&x.0.serialize()[..]);
r.0[64] = x.1.serialize();
@@ -395,15 +392,12 @@ impl From<(secp256k1::Signature, secp256k1::RecoveryId)> for Signature {
}
#[cfg(feature = "full_crypto")]
impl<'a> TryFrom<&'a Signature> for (secp256k1::Signature, secp256k1::RecoveryId) {
impl<'a> TryFrom<&'a Signature> for (libsecp256k1::Signature, libsecp256k1::RecoveryId) {
type Error = ();
fn try_from(
x: &'a Signature,
) -> Result<(secp256k1::Signature, secp256k1::RecoveryId), Self::Error> {
Ok((
secp256k1::Signature::parse_slice(&x.0[0..64]).expect("hardcoded to 64 bytes; qed"),
secp256k1::RecoveryId::parse(x.0[64]).map_err(|_| ())?,
))
) -> Result<(libsecp256k1::Signature, libsecp256k1::RecoveryId), Self::Error> {
parse_signature_standard(&x.0).map_err(|_| ())
}
}
@@ -457,7 +451,7 @@ impl TraitPair for Pair {
phrase: &str,
password: Option<&str>,
) -> Result<(Pair, Seed), SecretStringError> {
let big_seed = seed_from_entropy(
let big_seed = substrate_bip39::seed_from_entropy(
Mnemonic::from_phrase(phrase, Language::English)
.map_err(|_| SecretStringError::InvalidPhrase)?
.entropy(),
@@ -510,18 +504,18 @@ impl TraitPair for Pair {
/// Sign a message.
fn sign(&self, message: &[u8]) -> Signature {
let message = secp256k1::Message::parse(&blake2_256(message));
secp256k1::sign(&message, &self.secret).into()
let message = libsecp256k1::Message::parse(&blake2_256(message));
libsecp256k1::sign(&message, &self.secret).into()
}
/// Verify a signature on a message. Returns true if the signature is good.
fn verify<M: AsRef<[u8]>>(sig: &Self::Signature, message: M, pubkey: &Self::Public) -> bool {
let message = secp256k1::Message::parse(&blake2_256(message.as_ref()));
let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref()));
let sig: (_, _) = match sig.try_into() {
Ok(x) => x,
_ => return false,
};
match secp256k1::recover(&message, &sig.0, &sig.1) {
match libsecp256k1::recover(&message, &sig.0, &sig.1) {
Ok(actual) => pubkey.0[..] == actual.serialize_compressed()[..],
_ => false,
}
@@ -532,19 +526,15 @@ impl TraitPair for Pair {
/// This doesn't use the type system to ensure that `sig` and `pubkey` are the correct
/// size. Use it only if you're coming from byte buffers and need the speed.
fn verify_weak<P: AsRef<[u8]>, M: AsRef<[u8]>>(sig: &[u8], message: M, pubkey: P) -> bool {
let message = secp256k1::Message::parse(&blake2_256(message.as_ref()));
let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref()));
if sig.len() != 65 {
return false
}
let ri = match secp256k1::RecoveryId::parse(sig[64]) {
Ok(x) => x,
let (sig, ri) = match parse_signature_standard(&sig) {
Ok(sigri) => sigri,
_ => return false,
};
let sig = match secp256k1::Signature::parse_slice(&sig[0..64]) {
Ok(x) => x,
_ => return false,
};
match secp256k1::recover(&message, &sig, &ri) {
match libsecp256k1::recover(&message, &sig, &ri) {
Ok(actual) => pubkey.as_ref() == &actual.serialize()[1..],
_ => false,
}
@@ -577,25 +567,57 @@ impl Pair {
/// Sign a pre-hashed message
pub fn sign_prehashed(&self, message: &[u8; 32]) -> Signature {
let message = secp256k1::Message::parse(message);
secp256k1::sign(&message, &self.secret).into()
let message = libsecp256k1::Message::parse(message);
libsecp256k1::sign(&message, &self.secret).into()
}
/// Verify a signature on a pre-hashed message. Return `true` if the signature is valid
/// and thus matches the given `public` key.
pub fn verify_prehashed(sig: &Signature, message: &[u8; 32], public: &Public) -> bool {
let message = secp256k1::Message::parse(message);
let message = libsecp256k1::Message::parse(message);
let sig: (_, _) = match sig.try_into() {
Ok(x) => x,
_ => return false,
};
match secp256k1::recover(&message, &sig.0, &sig.1) {
match libsecp256k1::recover(&message, &sig.0, &sig.1) {
Ok(actual) => public.0[..] == actual.serialize_compressed()[..],
_ => false,
}
}
/// Verify a signature on a message. Returns true if the signature is good.
/// Parses Signature using parse_overflowing_slice
pub fn verify_deprecated<M: AsRef<[u8]>>(sig: &Signature, message: M, pubkey: &Public) -> bool {
let message = libsecp256k1::Message::parse(&blake2_256(message.as_ref()));
let (sig, ri) = match parse_signature_overflowing(&sig.0) {
Ok(sigri) => sigri,
_ => return false,
};
match libsecp256k1::recover(&message, &sig, &ri) {
Ok(actual) => pubkey.0[..] == actual.serialize_compressed()[..],
_ => false,
}
}
}
#[cfg(feature = "full_crypto")]
fn parse_signature_standard(
x: &[u8],
) -> Result<(libsecp256k1::Signature, libsecp256k1::RecoveryId), libsecp256k1::Error> {
let sig = libsecp256k1::Signature::parse_standard_slice(&x[..64])?;
let ri = libsecp256k1::RecoveryId::parse(x[64])?;
Ok((sig, ri))
}
#[cfg(feature = "full_crypto")]
fn parse_signature_overflowing(
x: &[u8],
) -> Result<(libsecp256k1::Signature, libsecp256k1::RecoveryId), libsecp256k1::Error> {
let sig = libsecp256k1::Signature::parse_overflowing_slice(&x[..64])?;
let ri = libsecp256k1::RecoveryId::parse(x[64])?;
Ok((sig, ri))
}
impl CryptoType for Public {
@@ -840,7 +862,7 @@ mod test {
let msg = [0u8; 32];
let sig1 = pair.sign_prehashed(&msg);
let sig2: Signature =
secp256k1::sign(&secp256k1::Message::parse(&msg), &pair.secret).into();
libsecp256k1::sign(&libsecp256k1::Message::parse(&msg), &pair.secret).into();
assert_eq!(sig1, sig2);
@@ -853,7 +875,7 @@ mod test {
let msg = keccak_256(b"this should be hashed");
let sig1 = pair.sign_prehashed(&msg);
let sig2: Signature =
secp256k1::sign(&secp256k1::Message::parse(&msg), &pair.secret).into();
libsecp256k1::sign(&libsecp256k1::Message::parse(&msg), &pair.secret).into();
assert_eq!(sig1, sig2);
}