mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-29 01:31:33 +00:00
core/src/: Validate PeerRecord signature matching peer ID (#2491)
Co-authored-by: Marco Munizaga <git@marcopolo.io>
This commit is contained in:
@ -6,7 +6,10 @@
|
||||
|
||||
- Implement `Display` on `DialError`. See [PR 2456].
|
||||
|
||||
- Validate PeerRecord signature matching peer ID. See [RUSTSEC-2022-0009].
|
||||
|
||||
[PR 2456]: https://github.com/libp2p/rust-libp2p/pull/2456
|
||||
[RUSTSEC-2022-0009]: https://rustsec.org/advisories/RUSTSEC-2022-0009.html
|
||||
|
||||
# 0.31.0 [2022-01-27]
|
||||
|
||||
|
@ -36,6 +36,11 @@ impl PeerRecord {
|
||||
let record = peer_record_proto::PeerRecord::decode(payload)?;
|
||||
|
||||
let peer_id = PeerId::from_bytes(&record.peer_id)?;
|
||||
|
||||
if peer_id != envelope.key.to_peer_id() {
|
||||
return Err(FromEnvelopeError::MismatchedSignature);
|
||||
}
|
||||
|
||||
let seq = record.seq;
|
||||
let addresses = record
|
||||
.addresses
|
||||
@ -126,6 +131,8 @@ pub enum FromEnvelopeError {
|
||||
InvalidPeerRecord(prost::DecodeError),
|
||||
/// Failed to decode the peer ID.
|
||||
InvalidPeerId(multihash::Error),
|
||||
/// The signer of the envelope is different than the peer id in the record.
|
||||
MismatchedSignature,
|
||||
/// Failed to decode a multi-address.
|
||||
InvalidMultiaddr(multiaddr::Error),
|
||||
}
|
||||
@ -162,6 +169,10 @@ impl fmt::Display for FromEnvelopeError {
|
||||
write!(f, "Failed to decode bytes as PeerRecord")
|
||||
}
|
||||
Self::InvalidPeerId(_) => write!(f, "Failed to decode bytes as PeerId"),
|
||||
Self::MismatchedSignature => write!(
|
||||
f,
|
||||
"The signer of the envelope is different than the peer id in the record"
|
||||
),
|
||||
Self::InvalidMultiaddr(_) => {
|
||||
write!(f, "Failed to decode bytes as MultiAddress")
|
||||
}
|
||||
@ -174,6 +185,7 @@ impl std::error::Error for FromEnvelopeError {
|
||||
match self {
|
||||
Self::InvalidPeerRecord(inner) => Some(inner),
|
||||
Self::InvalidPeerId(inner) => Some(inner),
|
||||
Self::MismatchedSignature => None,
|
||||
Self::InvalidMultiaddr(inner) => Some(inner),
|
||||
Self::BadPayload(inner) => Some(inner),
|
||||
}
|
||||
@ -196,4 +208,45 @@ mod tests {
|
||||
|
||||
assert_eq!(reconstructed, record)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mismatched_signature() {
|
||||
use prost::Message;
|
||||
|
||||
let addr: Multiaddr = HOME.parse().unwrap();
|
||||
|
||||
let envelope = {
|
||||
let identity_a = Keypair::generate_ed25519();
|
||||
let identity_b = Keypair::generate_ed25519();
|
||||
|
||||
let payload = {
|
||||
let record = peer_record_proto::PeerRecord {
|
||||
peer_id: identity_a.public().to_peer_id().to_bytes(),
|
||||
seq: 0,
|
||||
addresses: vec![peer_record_proto::peer_record::AddressInfo {
|
||||
multiaddr: addr.to_vec(),
|
||||
}],
|
||||
};
|
||||
|
||||
let mut buf = Vec::with_capacity(record.encoded_len());
|
||||
record
|
||||
.encode(&mut buf)
|
||||
.expect("Vec<u8> provides capacity as needed");
|
||||
buf
|
||||
};
|
||||
|
||||
SignedEnvelope::new(
|
||||
identity_b,
|
||||
String::from(DOMAIN_SEP),
|
||||
PAYLOAD_TYPE.as_bytes().to_vec(),
|
||||
payload,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
assert!(matches!(
|
||||
PeerRecord::from_signed_envelope(envelope),
|
||||
Err(FromEnvelopeError::MismatchedSignature)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use unsigned_varint::encode::usize_buffer;
|
||||
/// For more details see libp2p RFC0002: <https://github.com/libp2p/specs/blob/master/RFC/0002-signed-envelopes.md>
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct SignedEnvelope {
|
||||
key: PublicKey,
|
||||
pub(crate) key: PublicKey,
|
||||
payload_type: Vec<u8>,
|
||||
payload: Vec<u8>,
|
||||
signature: Vec<u8>,
|
||||
@ -201,3 +201,31 @@ impl fmt::Display for ReadPayloadError {
|
||||
}
|
||||
|
||||
impl std::error::Error for ReadPayloadError {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
pub fn test_roundtrip() {
|
||||
let kp = Keypair::generate_ed25519();
|
||||
let payload = "some payload".as_bytes();
|
||||
let domain_separation = "domain separation".to_string();
|
||||
let payload_type: Vec<u8> = "payload type".into();
|
||||
|
||||
let env = SignedEnvelope::new(
|
||||
kp.clone(),
|
||||
domain_separation.clone(),
|
||||
payload_type.clone(),
|
||||
payload.into(),
|
||||
)
|
||||
.expect("Failed to create envelope");
|
||||
|
||||
let actual_payload = env
|
||||
.payload(domain_separation, &payload_type)
|
||||
.expect("Failed to extract payload and public key");
|
||||
|
||||
assert_eq!(actual_payload, payload);
|
||||
assert_eq!(env.key, kp.public());
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user