core/src/: Validate PeerRecord signature matching peer ID (#2491)

Co-authored-by: Marco Munizaga <git@marcopolo.io>
This commit is contained in:
Max Inden
2022-02-09 16:39:02 +01:00
committed by GitHub
parent e6f034c132
commit 44d63d8ed4
3 changed files with 85 additions and 1 deletions

View File

@ -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]

View File

@ -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)
));
}
}

View File

@ -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());
}
}