diff --git a/identity/CHANGELOG.md b/identity/CHANGELOG.md index 9aacfac822d..14d6405743b 100644 --- a/identity/CHANGELOG.md +++ b/identity/CHANGELOG.md @@ -5,8 +5,12 @@ - Add support for exporting and importing ECDSA keys via the libp2p [protobuf format]. See [PR 3863]. +- Make `Keypair` and `PublicKey` opaque. + See [PR 3866]. + [PR 3715]: https://github.com/libp2p/rust-libp2p/pull/3715 [PR 3863]: https://github.com/libp2p/rust-libp2p/pull/3863 +[PR 3866]: https://github.com/libp2p/rust-libp2p/pull/3866 [protobuf format]: https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#keys ## 0.1.2 diff --git a/identity/Cargo.toml b/identity/Cargo.toml index 4a17e806554..d8a453cd5c4 100644 --- a/identity/Cargo.toml +++ b/identity/Cargo.toml @@ -20,7 +20,7 @@ log = "0.4" multiaddr = { version = "0.17.1", optional = true } multihash = { version = "0.17.0", default-features = false, features = ["std"], optional = true } p256 = { version = "0.13", default-features = false, features = ["ecdsa", "std", "pem"], optional = true } -quick-protobuf = { version = "0.8.1", optional = true } +quick-protobuf = "0.8.1" rand = { version = "0.8", optional = true } sec1 = { version = "0.7", default-features = false, optional = true } serde = { version = "1", optional = true, features = ["derive"] } @@ -33,10 +33,10 @@ zeroize = { version = "1.6", optional = true } ring = { version = "0.16.9", features = ["alloc", "std"], default-features = false, optional = true} [features] -secp256k1 = [ "dep:libsecp256k1", "dep:asn1_der", "dep:rand", "dep:sha2", "dep:zeroize", "dep:quick-protobuf" ] -ecdsa = [ "dep:p256", "dep:rand", "dep:void", "dep:zeroize", "dep:sec1", "dep:quick-protobuf" ] -rsa = [ "dep:ring", "dep:asn1_der", "dep:rand", "dep:zeroize", "dep:quick-protobuf" ] -ed25519 = [ "dep:ed25519-dalek", "dep:rand", "dep:zeroize", "dep:quick-protobuf" ] +secp256k1 = [ "dep:libsecp256k1", "dep:asn1_der", "dep:rand", "dep:sha2", "dep:zeroize" ] +ecdsa = [ "dep:p256", "dep:rand", "dep:void", "dep:zeroize", "dep:sec1" ] +rsa = [ "dep:ring", "dep:asn1_der", "dep:rand", "dep:zeroize" ] +ed25519 = [ "dep:ed25519-dalek", "dep:rand", "dep:zeroize" ] peerid = [ "dep:multihash", "dep:multiaddr", "dep:bs58", "dep:rand", "dep:thiserror", "dep:sha2" ] [dev-dependencies] diff --git a/identity/src/error.rs b/identity/src/error.rs index 0c86b346032..cb39e6ef312 100644 --- a/identity/src/error.rs +++ b/identity/src/error.rs @@ -33,6 +33,7 @@ pub struct DecodingError { } impl DecodingError { + #[allow(dead_code)] pub(crate) fn missing_feature(feature_name: &'static str) -> Self { Self { msg: format!("cargo feature `{feature_name}` is not enabled"), diff --git a/identity/src/keypair.rs b/identity/src/keypair.rs index e2cdb399788..a3128e56fbc 100644 --- a/identity/src/keypair.rs +++ b/identity/src/keypair.rs @@ -20,6 +20,12 @@ use crate::error::OtherVariantError; use crate::error::{DecodingError, SigningError}; +#[cfg(any( + feature = "ecdsa", + feature = "secp256k1", + feature = "ed25519", + feature = "rsa" +))] use crate::proto; use quick_protobuf::{BytesReader, Writer}; use std::convert::TryFrom; @@ -53,36 +59,25 @@ use crate::ecdsa; /// let keypair = Keypair::rsa_from_pkcs8(&mut bytes); /// ``` /// +#[derive(Debug, Clone)] +pub struct Keypair { + keypair: KeyPairInner, +} + #[derive(Debug, Clone)] #[allow(clippy::large_enum_variant)] -pub enum Keypair { +enum KeyPairInner { /// An Ed25519 keypair. #[cfg(feature = "ed25519")] - #[deprecated( - since = "0.1.0", - note = "This enum will be made opaque in the future, use `Keypair::try_into_ed25519` instead." - )] Ed25519(ed25519::Keypair), /// An RSA keypair. #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - #[deprecated( - since = "0.1.0", - note = "This enum will be made opaque in the future, use `Keypair::try_into_rsa` instead." - )] Rsa(rsa::Keypair), /// A Secp256k1 keypair. #[cfg(feature = "secp256k1")] - #[deprecated( - since = "0.1.0", - note = "This enum will be made opaque in the future, use `Keypair::try_into_secp256k1` instead." - )] Secp256k1(secp256k1::Keypair), /// An ECDSA keypair. #[cfg(feature = "ecdsa")] - #[deprecated( - since = "0.1.0", - note = "This enum will be made opaque in the future, use `Keypair::try_into_ecdsa` instead." - )] Ecdsa(ecdsa::Keypair), } @@ -90,22 +85,25 @@ impl Keypair { /// Generate a new Ed25519 keypair. #[cfg(feature = "ed25519")] pub fn generate_ed25519() -> Keypair { - #[allow(deprecated)] - Keypair::Ed25519(ed25519::Keypair::generate()) + Keypair { + keypair: KeyPairInner::Ed25519(ed25519::Keypair::generate()), + } } /// Generate a new Secp256k1 keypair. #[cfg(feature = "secp256k1")] pub fn generate_secp256k1() -> Keypair { - #[allow(deprecated)] - Keypair::Secp256k1(secp256k1::Keypair::generate()) + Keypair { + keypair: KeyPairInner::Secp256k1(secp256k1::Keypair::generate()), + } } /// Generate a new ECDSA keypair. #[cfg(feature = "ecdsa")] pub fn generate_ecdsa() -> Keypair { - #[allow(deprecated)] - Keypair::Ecdsa(ecdsa::Keypair::generate()) + Keypair { + keypair: KeyPairInner::Ecdsa(ecdsa::Keypair::generate()), + } } #[cfg(feature = "ed25519")] @@ -166,8 +164,9 @@ impl Keypair { /// [RFC5208]: https://tools.ietf.org/html/rfc5208#section-5 #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] pub fn rsa_from_pkcs8(pkcs8_der: &mut [u8]) -> Result { - #[allow(deprecated)] - rsa::Keypair::from_pkcs8(pkcs8_der).map(Keypair::Rsa) + rsa::Keypair::try_decode_pkcs8(pkcs8_der).map(|kp| Keypair { + keypair: KeyPairInner::Rsa(kp), + }) } /// Decode a keypair from a DER-encoded Secp256k1 secret key in an ECPrivateKey @@ -176,147 +175,198 @@ impl Keypair { /// [RFC5915]: https://tools.ietf.org/html/rfc5915 #[cfg(feature = "secp256k1")] pub fn secp256k1_from_der(der: &mut [u8]) -> Result { - #[allow(deprecated)] - secp256k1::SecretKey::from_der(der) - .map(|sk| Keypair::Secp256k1(secp256k1::Keypair::from(sk))) + secp256k1::SecretKey::from_der(der).map(|sk| Keypair { + keypair: KeyPairInner::Secp256k1(secp256k1::Keypair::from(sk)), + }) } #[cfg(feature = "ed25519")] pub fn ed25519_from_bytes(bytes: impl AsMut<[u8]>) -> Result { - #[allow(deprecated)] - Ok(Keypair::Ed25519(ed25519::Keypair::from( - ed25519::SecretKey::from_bytes(bytes)?, - ))) + Ok(Keypair { + keypair: KeyPairInner::Ed25519(ed25519::Keypair::from( + ed25519::SecretKey::try_from_bytes(bytes)?, + )), + }) } /// Sign a message using the private key of this keypair, producing /// a signature that can be verified using the corresponding public key. pub fn sign(&self, msg: &[u8]) -> Result, SigningError> { - use Keypair::*; - #[allow(deprecated)] - match self { + match self.keypair { #[cfg(feature = "ed25519")] - Ed25519(ref pair) => Ok(pair.sign(msg)), + KeyPairInner::Ed25519(ref pair) => Ok(pair.sign(msg)), #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - Rsa(ref pair) => pair.sign(msg), + KeyPairInner::Rsa(ref pair) => pair.sign(msg), #[cfg(feature = "secp256k1")] - Secp256k1(ref pair) => pair.secret().sign(msg), + KeyPairInner::Secp256k1(ref pair) => pair.secret().sign(msg), #[cfg(feature = "ecdsa")] - Ecdsa(ref pair) => Ok(pair.secret().sign(msg)), + KeyPairInner::Ecdsa(ref pair) => Ok(pair.secret().sign(msg)), } } /// Get the public key of this keypair. pub fn public(&self) -> PublicKey { - use Keypair::*; - #[allow(deprecated)] - match self { + match self.keypair { #[cfg(feature = "ed25519")] - Ed25519(pair) => PublicKey::Ed25519(pair.public()), + KeyPairInner::Ed25519(ref pair) => PublicKey { + publickey: PublicKeyInner::Ed25519(pair.public()), + }, #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - Rsa(pair) => PublicKey::Rsa(pair.public()), + KeyPairInner::Rsa(ref pair) => PublicKey { + publickey: PublicKeyInner::Rsa(pair.public()), + }, #[cfg(feature = "secp256k1")] - Secp256k1(pair) => PublicKey::Secp256k1(pair.public().clone()), + KeyPairInner::Secp256k1(ref pair) => PublicKey { + publickey: PublicKeyInner::Secp256k1(pair.public().clone()), + }, #[cfg(feature = "ecdsa")] - Ecdsa(pair) => PublicKey::Ecdsa(pair.public().clone()), + KeyPairInner::Ecdsa(ref pair) => PublicKey { + publickey: PublicKeyInner::Ecdsa(pair.public().clone()), + }, } } /// Encode a private key as protobuf structure. pub fn to_protobuf_encoding(&self) -> Result, DecodingError> { - use quick_protobuf::MessageWrite; + #[cfg(any( + feature = "ecdsa", + feature = "secp256k1", + feature = "ed25519", + feature = "rsa" + ))] + { + use quick_protobuf::MessageWrite; + let pk: proto::PrivateKey = match self.keypair { + #[cfg(feature = "ed25519")] + KeyPairInner::Ed25519(ref data) => proto::PrivateKey { + Type: proto::KeyType::Ed25519, + Data: data.to_bytes().to_vec(), + }, + #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] + KeyPairInner::Rsa(_) => return Err(DecodingError::encoding_unsupported("RSA")), + #[cfg(feature = "secp256k1")] + KeyPairInner::Secp256k1(ref data) => proto::PrivateKey { + Type: proto::KeyType::Secp256k1, + Data: data.secret().to_bytes().to_vec(), + }, + #[cfg(feature = "ecdsa")] + KeyPairInner::Ecdsa(ref data) => proto::PrivateKey { + Type: proto::KeyType::ECDSA, + Data: data.secret().encode_der(), + }, + }; - #[allow(deprecated)] - let pk: proto::PrivateKey = match self { - #[cfg(feature = "ed25519")] - Self::Ed25519(data) => proto::PrivateKey { - Type: proto::KeyType::Ed25519, - Data: data.to_bytes().to_vec(), - }, - #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - Self::Rsa(_) => return Err(DecodingError::encoding_unsupported("RSA")), - #[cfg(feature = "secp256k1")] - Self::Secp256k1(data) => proto::PrivateKey { - Type: proto::KeyType::Secp256k1, - Data: data.secret().to_bytes().to_vec(), - }, - #[cfg(feature = "ecdsa")] - Self::Ecdsa(data) => proto::PrivateKey { - Type: proto::KeyType::ECDSA, - Data: data.secret().encode_der(), - }, - }; + let mut buf = Vec::with_capacity(pk.get_size()); + let mut writer = Writer::new(&mut buf); + pk.write_message(&mut writer).expect("Encoding to succeed"); - let mut buf = Vec::with_capacity(pk.get_size()); - let mut writer = Writer::new(&mut buf); - pk.write_message(&mut writer).expect("Encoding to succeed"); + Ok(buf) + } - Ok(buf) + #[cfg(not(any( + feature = "ecdsa", + feature = "secp256k1", + feature = "ed25519", + feature = "rsa" + )))] + unreachable!() } /// Decode a private key from a protobuf structure and parse it as a [`Keypair`]. + #[allow(unused_variables)] pub fn from_protobuf_encoding(bytes: &[u8]) -> Result { - use quick_protobuf::MessageRead; - - let mut reader = BytesReader::from_bytes(bytes); - let mut private_key = proto::PrivateKey::from_reader(&mut reader, bytes) - .map_err(|e| DecodingError::bad_protobuf("private key bytes", e)) - .map(zeroize::Zeroizing::new)?; - - #[allow(deprecated, unreachable_code)] - match private_key.Type { - proto::KeyType::Ed25519 => { - #[cfg(feature = "ed25519")] - return ed25519::Keypair::try_from_bytes(&mut private_key.Data) - .map(Keypair::Ed25519); - Err(DecodingError::missing_feature("ed25519")) - } - proto::KeyType::RSA => Err(DecodingError::decoding_unsupported("RSA")), - proto::KeyType::Secp256k1 => { - #[cfg(feature = "secp256k1")] - return secp256k1::SecretKey::try_from_bytes(&mut private_key.Data) - .map(|key| Keypair::Secp256k1(key.into())); - Err(DecodingError::missing_feature("secp256k1")) - } - proto::KeyType::ECDSA => { - #[cfg(feature = "ecdsa")] - return ecdsa::SecretKey::try_decode_der(&mut private_key.Data) - .map(|key| Keypair::Ecdsa(key.into())); - Err(DecodingError::missing_feature("ecdsa")) + #[cfg(any( + feature = "ecdsa", + feature = "secp256k1", + feature = "ed25519", + feature = "rsa" + ))] + { + use quick_protobuf::MessageRead; + + let mut reader = BytesReader::from_bytes(bytes); + let mut private_key = proto::PrivateKey::from_reader(&mut reader, bytes) + .map_err(|e| DecodingError::bad_protobuf("private key bytes", e)) + .map(zeroize::Zeroizing::new)?; + + #[allow(unreachable_code)] + match private_key.Type { + proto::KeyType::Ed25519 => { + #[cfg(feature = "ed25519")] + return ed25519::Keypair::try_from_bytes(&mut private_key.Data).map(|sk| { + Keypair { + keypair: KeyPairInner::Ed25519(sk), + } + }); + Err(DecodingError::missing_feature("ed25519")) + } + proto::KeyType::RSA => Err(DecodingError::decoding_unsupported("RSA")), + proto::KeyType::Secp256k1 => { + #[cfg(feature = "secp256k1")] + return secp256k1::SecretKey::try_from_bytes(&mut private_key.Data).map( + |key| Keypair { + keypair: KeyPairInner::Secp256k1(key.into()), + }, + ); + + Err(DecodingError::missing_feature("secp256k1")) + } + proto::KeyType::ECDSA => { + #[cfg(feature = "ecdsa")] + return ecdsa::SecretKey::try_decode_der(&mut private_key.Data).map(|key| { + Keypair { + keypair: KeyPairInner::Ecdsa(key.into()), + } + }); + + Err(DecodingError::missing_feature("ecdsa")) + } } } + + #[cfg(not(any( + feature = "ecdsa", + feature = "secp256k1", + feature = "ed25519", + feature = "rsa" + )))] + unreachable!() } } #[cfg(feature = "ecdsa")] impl From for Keypair { fn from(kp: ecdsa::Keypair) -> Self { - #[allow(deprecated)] - Keypair::Ecdsa(kp) + Keypair { + keypair: KeyPairInner::Ecdsa(kp), + } } } #[cfg(feature = "ed25519")] impl From for Keypair { fn from(kp: ed25519::Keypair) -> Self { - #[allow(deprecated)] - Keypair::Ed25519(kp) + Keypair { + keypair: KeyPairInner::Ed25519(kp), + } } } #[cfg(feature = "secp256k1")] impl From for Keypair { fn from(kp: secp256k1::Keypair) -> Self { - #[allow(deprecated)] - Keypair::Secp256k1(kp) + Keypair { + keypair: KeyPairInner::Secp256k1(kp), + } } } #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] impl From for Keypair { fn from(kp: rsa::Keypair) -> Self { - #[allow(deprecated)] - Keypair::Rsa(kp) + Keypair { + keypair: KeyPairInner::Rsa(kp), + } } } @@ -325,15 +375,14 @@ impl TryInto for Keypair { type Error = OtherVariantError; fn try_into(self) -> Result { - #[allow(deprecated)] - match self { - Keypair::Ed25519(inner) => Ok(inner), + match self.keypair { + KeyPairInner::Ed25519(inner) => Ok(inner), #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - Keypair::Rsa(_) => Err(OtherVariantError::new(crate::KeyType::RSA)), + KeyPairInner::Rsa(_) => Err(OtherVariantError::new(crate::KeyType::RSA)), #[cfg(feature = "secp256k1")] - Keypair::Secp256k1(_) => Err(OtherVariantError::new(crate::KeyType::Secp256k1)), + KeyPairInner::Secp256k1(_) => Err(OtherVariantError::new(crate::KeyType::Secp256k1)), #[cfg(feature = "ecdsa")] - Keypair::Ecdsa(_) => Err(OtherVariantError::new(crate::KeyType::Ecdsa)), + KeyPairInner::Ecdsa(_) => Err(OtherVariantError::new(crate::KeyType::Ecdsa)), } } } @@ -343,15 +392,14 @@ impl TryInto for Keypair { type Error = OtherVariantError; fn try_into(self) -> Result { - #[allow(deprecated)] - match self { - Keypair::Ecdsa(inner) => Ok(inner), + match self.keypair { + KeyPairInner::Ecdsa(inner) => Ok(inner), #[cfg(feature = "ed25519")] - Keypair::Ed25519(_) => Err(OtherVariantError::new(crate::KeyType::Ed25519)), + KeyPairInner::Ed25519(_) => Err(OtherVariantError::new(crate::KeyType::Ed25519)), #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - Keypair::Rsa(_) => Err(OtherVariantError::new(crate::KeyType::RSA)), + KeyPairInner::Rsa(_) => Err(OtherVariantError::new(crate::KeyType::RSA)), #[cfg(feature = "secp256k1")] - Keypair::Secp256k1(_) => Err(OtherVariantError::new(crate::KeyType::Secp256k1)), + KeyPairInner::Secp256k1(_) => Err(OtherVariantError::new(crate::KeyType::Secp256k1)), } } } @@ -361,15 +409,14 @@ impl TryInto for Keypair { type Error = OtherVariantError; fn try_into(self) -> Result { - #[allow(deprecated)] - match self { - Keypair::Secp256k1(inner) => Ok(inner), + match self.keypair { + KeyPairInner::Secp256k1(inner) => Ok(inner), #[cfg(feature = "ed25519")] - Keypair::Ed25519(_) => Err(OtherVariantError::new(crate::KeyType::Ed25519)), + KeyPairInner::Ed25519(_) => Err(OtherVariantError::new(crate::KeyType::Ed25519)), #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - Keypair::Rsa(_) => Err(OtherVariantError::new(crate::KeyType::RSA)), + KeyPairInner::Rsa(_) => Err(OtherVariantError::new(crate::KeyType::RSA)), #[cfg(feature = "ecdsa")] - Keypair::Ecdsa(_) => Err(OtherVariantError::new(crate::KeyType::Ecdsa)), + KeyPairInner::Ecdsa(_) => Err(OtherVariantError::new(crate::KeyType::Ecdsa)), } } } @@ -379,71 +426,57 @@ impl TryInto for Keypair { type Error = OtherVariantError; fn try_into(self) -> Result { - #[allow(deprecated)] - match self { - Keypair::Rsa(inner) => Ok(inner), + match self.keypair { + KeyPairInner::Rsa(inner) => Ok(inner), #[cfg(feature = "ed25519")] - Keypair::Ed25519(_) => Err(OtherVariantError::new(crate::KeyType::Ed25519)), + KeyPairInner::Ed25519(_) => Err(OtherVariantError::new(crate::KeyType::Ed25519)), #[cfg(feature = "secp256k1")] - Keypair::Secp256k1(_) => Err(OtherVariantError::new(crate::KeyType::Secp256k1)), + KeyPairInner::Secp256k1(_) => Err(OtherVariantError::new(crate::KeyType::Secp256k1)), #[cfg(feature = "ecdsa")] - Keypair::Ecdsa(_) => Err(OtherVariantError::new(crate::KeyType::Ecdsa)), + KeyPairInner::Ecdsa(_) => Err(OtherVariantError::new(crate::KeyType::Ecdsa)), } } } -/// The public key of a node's identity keypair. #[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum PublicKey { +pub(crate) enum PublicKeyInner { /// A public Ed25519 key. #[cfg(feature = "ed25519")] - #[deprecated( - since = "0.1.0", - note = "This enum will be made opaque in the future, use `PublicKey::from` and `PublicKey::into_ed25519` instead." - )] Ed25519(ed25519::PublicKey), #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] /// A public RSA key. - - #[deprecated( - since = "0.1.0", - note = "This enum will be made opaque in the future, use `PublicKey::from` and `PublicKey::into_rsa` instead." - )] Rsa(rsa::PublicKey), #[cfg(feature = "secp256k1")] /// A public Secp256k1 key. - #[deprecated( - since = "0.1.0", - note = "This enum will be made opaque in the future, use `PublicKey::from` and `PublicKey::into_secp256k1` instead." - )] Secp256k1(secp256k1::PublicKey), /// A public ECDSA key. #[cfg(feature = "ecdsa")] - #[deprecated( - since = "0.1.0", - note = "This enum will be made opaque in the future, use `PublicKey::from` and `PublicKey::into_ecdsa` instead." - )] Ecdsa(ecdsa::PublicKey), } +/// The public key of a node's identity keypair. +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct PublicKey { + pub(crate) publickey: PublicKeyInner, +} + impl PublicKey { /// Verify a signature for a message using this public key, i.e. check /// that the signature has been produced by the corresponding /// private key (authenticity), and that the message has not been /// tampered with (integrity). #[must_use] + #[allow(unused_variables)] pub fn verify(&self, msg: &[u8], sig: &[u8]) -> bool { - use PublicKey::*; - #[allow(deprecated)] - match self { + match self.publickey { #[cfg(feature = "ed25519")] - Ed25519(pk) => pk.verify(msg, sig), + PublicKeyInner::Ed25519(ref pk) => pk.verify(msg, sig), #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - Rsa(pk) => pk.verify(msg, sig), + PublicKeyInner::Rsa(ref pk) => pk.verify(msg, sig), #[cfg(feature = "secp256k1")] - Secp256k1(pk) => pk.verify(msg, sig), + PublicKeyInner::Secp256k1(ref pk) => pk.verify(msg, sig), #[cfg(feature = "ecdsa")] - Ecdsa(pk) => pk.verify(msg, sig), + PublicKeyInner::Ecdsa(ref pk) => pk.verify(msg, sig), } } @@ -509,17 +542,32 @@ impl PublicKey { /// Encode the public key into a protobuf structure for storage or /// exchange with other nodes. pub fn encode_protobuf(&self) -> Vec { - use quick_protobuf::MessageWrite; - - let public_key = proto::PublicKey::from(self); - - let mut buf = Vec::with_capacity(public_key.get_size()); - let mut writer = Writer::new(&mut buf); - public_key - .write_message(&mut writer) - .expect("Encoding to succeed"); + #[cfg(any( + feature = "ecdsa", + feature = "secp256k1", + feature = "ed25519", + feature = "rsa" + ))] + { + use quick_protobuf::MessageWrite; + let public_key = proto::PublicKey::from(self); + + let mut buf = Vec::with_capacity(public_key.get_size()); + let mut writer = Writer::new(&mut buf); + public_key + .write_message(&mut writer) + .expect("Encoding to succeed"); + + buf + } - buf + #[cfg(not(any( + feature = "ecdsa", + feature = "secp256k1", + feature = "ed25519", + feature = "rsa" + )))] + unreachable!() } /// Decode a public key from a protobuf structure, e.g. read from storage @@ -533,15 +581,31 @@ impl PublicKey { /// Decode a public key from a protobuf structure, e.g. read from storage /// or received from another node. + #[allow(unused_variables)] pub fn try_decode_protobuf(bytes: &[u8]) -> Result { - use quick_protobuf::MessageRead; - - let mut reader = BytesReader::from_bytes(bytes); - - let pubkey = proto::PublicKey::from_reader(&mut reader, bytes) - .map_err(|e| DecodingError::bad_protobuf("public key bytes", e))?; + #[cfg(any( + feature = "ecdsa", + feature = "secp256k1", + feature = "ed25519", + feature = "rsa" + ))] + { + use quick_protobuf::MessageRead; + let mut reader = BytesReader::from_bytes(bytes); + + let pubkey = proto::PublicKey::from_reader(&mut reader, bytes) + .map_err(|e| DecodingError::bad_protobuf("public key bytes", e))?; + + pubkey.try_into() + } - pubkey.try_into() + #[cfg(not(any( + feature = "ecdsa", + feature = "secp256k1", + feature = "ed25519", + feature = "rsa" + )))] + unreachable!() } /// Convert the `PublicKey` into the corresponding `PeerId`. @@ -551,41 +615,57 @@ impl PublicKey { } } +#[cfg(any( + feature = "ecdsa", + feature = "secp256k1", + feature = "ed25519", + feature = "rsa" +))] impl TryFrom for PublicKey { type Error = DecodingError; fn try_from(pubkey: proto::PublicKey) -> Result { - #[allow(deprecated)] match pubkey.Type { #[cfg(feature = "ed25519")] - proto::KeyType::Ed25519 => { - ed25519::PublicKey::decode(&pubkey.Data).map(PublicKey::Ed25519) - } + proto::KeyType::Ed25519 => Ok(ed25519::PublicKey::try_from_bytes(&pubkey.Data).map( + |kp| PublicKey { + publickey: PublicKeyInner::Ed25519(kp), + }, + )?), #[cfg(not(feature = "ed25519"))] proto::KeyType::Ed25519 => { log::debug!("support for ed25519 was disabled at compile-time"); Err(DecodingError::missing_feature("ed25519")) } #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - proto::KeyType::RSA => rsa::PublicKey::decode_x509(&pubkey.Data).map(PublicKey::Rsa), + proto::KeyType::RSA => { + Ok( + rsa::PublicKey::try_decode_x509(&pubkey.Data).map(|kp| PublicKey { + publickey: PublicKeyInner::Rsa(kp), + })?, + ) + } #[cfg(any(not(feature = "rsa"), target_arch = "wasm32"))] proto::KeyType::RSA => { log::debug!("support for RSA was disabled at compile-time"); Err(DecodingError::missing_feature("rsa")) } #[cfg(feature = "secp256k1")] - proto::KeyType::Secp256k1 => { - secp256k1::PublicKey::decode(&pubkey.Data).map(PublicKey::Secp256k1) - } + proto::KeyType::Secp256k1 => Ok(secp256k1::PublicKey::try_from_bytes(&pubkey.Data) + .map(|kp| PublicKey { + publickey: PublicKeyInner::Secp256k1(kp), + })?), #[cfg(not(feature = "secp256k1"))] proto::KeyType::Secp256k1 => { log::debug!("support for secp256k1 was disabled at compile-time"); Err(DecodingError::missing_feature("secp256k1")) } #[cfg(feature = "ecdsa")] - proto::KeyType::ECDSA => { - ecdsa::PublicKey::decode_der(&pubkey.Data).map(PublicKey::Ecdsa) - } + proto::KeyType::ECDSA => Ok(ecdsa::PublicKey::try_decode_der(&pubkey.Data).map( + |kp| PublicKey { + publickey: PublicKeyInner::Ecdsa(kp), + }, + )?), #[cfg(not(feature = "ecdsa"))] proto::KeyType::ECDSA => { log::debug!("support for ECDSA was disabled at compile-time"); @@ -600,15 +680,14 @@ impl TryInto for PublicKey { type Error = OtherVariantError; fn try_into(self) -> Result { - #[allow(deprecated)] - match self { - PublicKey::Ed25519(inner) => Ok(inner), + match self.publickey { + PublicKeyInner::Ed25519(inner) => Ok(inner), #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - PublicKey::Rsa(_) => Err(OtherVariantError::new(crate::KeyType::RSA)), + PublicKeyInner::Rsa(_) => Err(OtherVariantError::new(crate::KeyType::RSA)), #[cfg(feature = "secp256k1")] - PublicKey::Secp256k1(_) => Err(OtherVariantError::new(crate::KeyType::Secp256k1)), + PublicKeyInner::Secp256k1(_) => Err(OtherVariantError::new(crate::KeyType::Secp256k1)), #[cfg(feature = "ecdsa")] - PublicKey::Ecdsa(_) => Err(OtherVariantError::new(crate::KeyType::Ecdsa)), + PublicKeyInner::Ecdsa(_) => Err(OtherVariantError::new(crate::KeyType::Ecdsa)), } } } @@ -618,15 +697,14 @@ impl TryInto for PublicKey { type Error = OtherVariantError; fn try_into(self) -> Result { - #[allow(deprecated)] - match self { - PublicKey::Ecdsa(inner) => Ok(inner), + match self.publickey { + PublicKeyInner::Ecdsa(inner) => Ok(inner), #[cfg(feature = "ed25519")] - PublicKey::Ed25519(_) => Err(OtherVariantError::new(crate::KeyType::Ed25519)), + PublicKeyInner::Ed25519(_) => Err(OtherVariantError::new(crate::KeyType::Ed25519)), #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - PublicKey::Rsa(_) => Err(OtherVariantError::new(crate::KeyType::RSA)), + PublicKeyInner::Rsa(_) => Err(OtherVariantError::new(crate::KeyType::RSA)), #[cfg(feature = "secp256k1")] - PublicKey::Secp256k1(_) => Err(OtherVariantError::new(crate::KeyType::Secp256k1)), + PublicKeyInner::Secp256k1(_) => Err(OtherVariantError::new(crate::KeyType::Secp256k1)), } } } @@ -636,15 +714,14 @@ impl TryInto for PublicKey { type Error = OtherVariantError; fn try_into(self) -> Result { - #[allow(deprecated)] - match self { - PublicKey::Secp256k1(inner) => Ok(inner), + match self.publickey { + PublicKeyInner::Secp256k1(inner) => Ok(inner), #[cfg(feature = "ed25519")] - PublicKey::Ed25519(_) => Err(OtherVariantError::new(crate::KeyType::Ed25519)), + PublicKeyInner::Ed25519(_) => Err(OtherVariantError::new(crate::KeyType::Ed25519)), #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - PublicKey::Rsa(_) => Err(OtherVariantError::new(crate::KeyType::RSA)), + PublicKeyInner::Rsa(_) => Err(OtherVariantError::new(crate::KeyType::RSA)), #[cfg(feature = "ecdsa")] - PublicKey::Ecdsa(_) => Err(OtherVariantError::new(crate::KeyType::Ecdsa)), + PublicKeyInner::Ecdsa(_) => Err(OtherVariantError::new(crate::KeyType::Ecdsa)), } } } @@ -654,15 +731,14 @@ impl TryInto for PublicKey { type Error = OtherVariantError; fn try_into(self) -> Result { - #[allow(deprecated)] - match self { - PublicKey::Rsa(inner) => Ok(inner), + match self.publickey { + PublicKeyInner::Rsa(inner) => Ok(inner), #[cfg(feature = "ed25519")] - PublicKey::Ed25519(_) => Err(OtherVariantError::new(crate::KeyType::Ed25519)), + PublicKeyInner::Ed25519(_) => Err(OtherVariantError::new(crate::KeyType::Ed25519)), #[cfg(feature = "secp256k1")] - PublicKey::Secp256k1(_) => Err(OtherVariantError::new(crate::KeyType::Secp256k1)), + PublicKeyInner::Secp256k1(_) => Err(OtherVariantError::new(crate::KeyType::Secp256k1)), #[cfg(feature = "ecdsa")] - PublicKey::Ecdsa(_) => Err(OtherVariantError::new(crate::KeyType::Ecdsa)), + PublicKeyInner::Ecdsa(_) => Err(OtherVariantError::new(crate::KeyType::Ecdsa)), } } } @@ -670,32 +746,36 @@ impl TryInto for PublicKey { #[cfg(feature = "ed25519")] impl From for PublicKey { fn from(key: ed25519::PublicKey) -> Self { - #[allow(deprecated)] // TODO: Remove when PublicKey::Ed25519 is made opaque - PublicKey::Ed25519(key) + PublicKey { + publickey: PublicKeyInner::Ed25519(key), + } } } #[cfg(feature = "secp256k1")] impl From for PublicKey { fn from(key: secp256k1::PublicKey) -> Self { - #[allow(deprecated)] // TODO: Remove when PublicKey::Secp256k1 is made opaque - PublicKey::Secp256k1(key) + PublicKey { + publickey: PublicKeyInner::Secp256k1(key), + } } } #[cfg(feature = "ecdsa")] impl From for PublicKey { fn from(key: ecdsa::PublicKey) -> Self { - #[allow(deprecated)] // TODO: Remove when PublicKey::Ecdsa is made opaque - PublicKey::Ecdsa(key) + PublicKey { + publickey: PublicKeyInner::Ecdsa(key), + } } } #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] impl From for PublicKey { fn from(key: rsa::PublicKey) -> Self { - #[allow(deprecated)] // TODO: Remove when PublicKey::Rsa is made opaque - PublicKey::Rsa(key) + PublicKey { + publickey: PublicKeyInner::Rsa(key), + } } } @@ -773,7 +853,13 @@ mod tests { } #[test] - #[cfg(feature = "peerid")] + #[cfg(all( + feature = "ecdsa", + feature = "secp256k1", + feature = "ed25519", + feature = "rsa", + feature = "peerid" + ))] fn keypair_from_protobuf_encoding() { // E.g. retrieved from an IPFS config file. let base_64_encoded = "CAESQL6vdKQuznQosTrW7FWI9At+XX7EBf0BnZLhb6w+N+XSQSdfInl6c7U4NuxXJlhKcRBlBw9d0tj2dfBIVf6mcPA="; diff --git a/identity/src/keypair_dummy.rs b/identity/src/keypair_dummy.rs deleted file mode 100644 index 4e1bb61f15c..00000000000 --- a/identity/src/keypair_dummy.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2023 Protocol Labs. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -use crate::error::{DecodingError, SigningError}; - -#[derive(Debug, Clone)] -pub enum Keypair {} - -impl Keypair { - pub fn sign(&self, _: &[u8]) -> Result, SigningError> { - unreachable!("Can never construct empty enum") - } - - pub fn public(&self) -> PublicKey { - unreachable!("Can never construct empty enum") - } - - pub fn to_protobuf_encoding(&self) -> Result, DecodingError> { - unreachable!("Can never construct empty enum") - } - - pub fn from_protobuf_encoding(_: &[u8]) -> Result { - Err(DecodingError::missing_feature( - "ecdsa|rsa|ed25519|secp256k1", - )) - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub enum PublicKey {} - -impl PublicKey { - #[must_use] - pub fn verify(&self, _: &[u8], _: &[u8]) -> bool { - unreachable!("Can never construct empty enum") - } - - pub fn to_protobuf_encoding(&self) -> Vec { - unreachable!("Can never construct empty enum") - } - - pub fn from_protobuf_encoding(_: &[u8]) -> Result { - Err(DecodingError::missing_feature( - "ecdsa|rsa|ed25519|secp256k1", - )) - } - - #[cfg(feature = "peerid")] - pub fn to_peer_id(&self) -> crate::PeerId { - unreachable!("Can never construct empty enum") - } -} diff --git a/identity/src/lib.rs b/identity/src/lib.rs index ea9ced51622..9a6c42374f6 100644 --- a/identity/src/lib.rs +++ b/identity/src/lib.rs @@ -60,20 +60,6 @@ pub mod rsa; pub mod secp256k1; mod error; -#[cfg(any( - feature = "ecdsa", - feature = "secp256k1", - feature = "ed25519", - feature = "rsa" -))] -mod keypair; -#[cfg(all( - not(feature = "ecdsa"), - not(feature = "secp256k1"), - not(feature = "ed25519"), - not(feature = "rsa") -))] -#[path = "./keypair_dummy.rs"] mod keypair; #[cfg(feature = "peerid")] mod peer_id; @@ -98,25 +84,24 @@ impl zeroize::Zeroize for proto::PrivateKey { ))] impl From<&PublicKey> for proto::PublicKey { fn from(key: &PublicKey) -> Self { - #[allow(deprecated)] - match key { + match &key.publickey { #[cfg(feature = "ed25519")] - PublicKey::Ed25519(key) => proto::PublicKey { + keypair::PublicKeyInner::Ed25519(key) => proto::PublicKey { Type: proto::KeyType::Ed25519, - Data: key.encode().to_vec(), + Data: key.to_bytes().to_vec(), }, #[cfg(all(feature = "rsa", not(target_arch = "wasm32")))] - PublicKey::Rsa(key) => proto::PublicKey { + keypair::PublicKeyInner::Rsa(key) => proto::PublicKey { Type: proto::KeyType::RSA, Data: key.encode_x509(), }, #[cfg(feature = "secp256k1")] - PublicKey::Secp256k1(key) => proto::PublicKey { + keypair::PublicKeyInner::Secp256k1(key) => proto::PublicKey { Type: proto::KeyType::Secp256k1, - Data: key.encode().to_vec(), + Data: key.to_bytes().to_vec(), }, #[cfg(feature = "ecdsa")] - PublicKey::Ecdsa(key) => proto::PublicKey { + keypair::PublicKeyInner::Ecdsa(key) => proto::PublicKey { Type: proto::KeyType::ECDSA, Data: key.encode_der(), }, diff --git a/identity/src/peer_id.rs b/identity/src/peer_id.rs index 51d9e4f1f6d..184b75aa785 100644 --- a/identity/src/peer_id.rs +++ b/identity/src/peer_id.rs @@ -307,7 +307,6 @@ mod tests { .parse() .unwrap(); - #[allow(deprecated)] let peer_id = PeerId::try_from_multiaddr(&address).unwrap(); assert_eq!( @@ -322,7 +321,6 @@ mod tests { fn no_panic_on_extract_peer_id_from_multi_address_if_not_present() { let address = "/memory/1234".to_string().parse().unwrap(); - #[allow(deprecated)] let maybe_empty = PeerId::try_from_multiaddr(&address); assert!(maybe_empty.is_none()); diff --git a/transports/noise/src/protocol/x25519.rs b/transports/noise/src/protocol/x25519.rs index 4a572945ef8..4fd19097c74 100644 --- a/transports/noise/src/protocol/x25519.rs +++ b/transports/noise/src/protocol/x25519.rs @@ -127,8 +127,8 @@ impl Protocol for X25519 { #[allow(irrefutable_let_patterns)] fn linked(id_pk: &identity::PublicKey, dh_pk: &PublicKey) -> bool { - if let identity::PublicKey::Ed25519(ref p) = id_pk { - PublicKey::from_ed25519(p).as_ref() == dh_pk.as_ref() + if let Ok(p) = identity::PublicKey::try_into_ed25519(id_pk.clone()) { + PublicKey::from_ed25519(&p).as_ref() == dh_pk.as_ref() } else { false } @@ -161,20 +161,16 @@ impl Keypair { /// > * [Noise: Static Key Reuse](http://www.noiseprotocol.org/noise.html#security-considerations) #[allow(unreachable_patterns)] pub fn from_identity(id_keys: &identity::Keypair) -> Option> { - match id_keys { - identity::Keypair::Ed25519(p) => { - let kp = Keypair::from(SecretKey::from_ed25519(&p.secret())); - let id = KeypairIdentity { - public: id_keys.public(), - signature: None, - }; - Some(AuthenticKeypair { - keypair: kp, - identity: id, - }) - } - _ => None, - } + let ed25519_keypair = id_keys.clone().try_into_ed25519().ok()?; + let kp = Keypair::from(SecretKey::from_ed25519(&ed25519_keypair.secret())); + let id = KeypairIdentity { + public: id_keys.public(), + signature: None, + }; + Some(AuthenticKeypair { + keypair: kp, + identity: id, + }) } }