Verify event signatures before adding log entries
This commit is contained in:
@ -8,7 +8,7 @@
|
|||||||
use std::thread::JoinHandle;
|
use std::thread::JoinHandle;
|
||||||
use std::sync::mpsc::{Receiver, Sender};
|
use std::sync::mpsc::{Receiver, Sender};
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
use log::{hash, hash_event, Entry, Event, Sha256Hash};
|
use log::{hash, hash_event, verify_event, Entry, Event, Sha256Hash};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
pub struct Historian<T> {
|
pub struct Historian<T> {
|
||||||
@ -61,8 +61,10 @@ fn log_events<T: Serialize + Clone>(
|
|||||||
}
|
}
|
||||||
match receiver.try_recv() {
|
match receiver.try_recv() {
|
||||||
Ok(event) => {
|
Ok(event) => {
|
||||||
|
if verify_event(&event) {
|
||||||
log_event(sender, num_hashes, end_hash, event)?;
|
log_event(sender, num_hashes, end_hash, event)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Err(TryRecvError::Empty) => {
|
Err(TryRecvError::Empty) => {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -184,4 +186,24 @@ mod tests {
|
|||||||
assert!(entries.len() > 1);
|
assert!(entries.len() > 1);
|
||||||
assert!(verify_slice(&entries, &zero));
|
assert!(verify_slice(&entries, &zero));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_bad_event_attack() {
|
||||||
|
let zero = Sha256Hash::default();
|
||||||
|
let hist = Historian::new(&zero, None);
|
||||||
|
let keypair = generate_keypair();
|
||||||
|
let mut event0 = sign_hash(hash(b"hello, world"), &keypair);
|
||||||
|
if let Event::Claim { key, sig, .. } = event0 {
|
||||||
|
let data = hash(b"goodbye cruel world");
|
||||||
|
event0 = Event::Claim { key, data, sig };
|
||||||
|
}
|
||||||
|
hist.sender.send(event0).unwrap();
|
||||||
|
drop(hist.sender);
|
||||||
|
assert_eq!(
|
||||||
|
hist.thread_hdl.join().unwrap().1,
|
||||||
|
ExitReason::RecvDisconnected
|
||||||
|
);
|
||||||
|
let entries: Vec<Entry<Sha256Hash>> = hist.receiver.iter().collect();
|
||||||
|
assert_eq!(entries.len(), 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
17
src/log.rs
17
src/log.rs
@ -187,11 +187,9 @@ pub fn next_tick<T: Serialize>(start_hash: &Sha256Hash, num_hashes: u64) -> Entr
|
|||||||
next_entry(start_hash, num_hashes, Event::Tick)
|
next_entry(start_hash, num_hashes, Event::Tick)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verifies self.end_hash is the result of hashing a 'start_hash' 'self.num_hashes' times.
|
pub fn verify_event<T: Serialize>(event: &Event<T>) -> bool {
|
||||||
/// If the event is not a Tick, then hash that as well.
|
|
||||||
pub fn verify_entry<T: Serialize>(entry: &Entry<T>, start_hash: &Sha256Hash) -> bool {
|
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
if let Event::Claim { key, ref data, sig } = entry.event {
|
if let Event::Claim { key, ref data, sig } = *event {
|
||||||
let mut claim_data = serialize(&data).unwrap();
|
let mut claim_data = serialize(&data).unwrap();
|
||||||
if !verify_signature(&key, &claim_data, &sig) {
|
if !verify_signature(&key, &claim_data, &sig) {
|
||||||
return false;
|
return false;
|
||||||
@ -202,7 +200,7 @@ pub fn verify_entry<T: Serialize>(entry: &Entry<T>, start_hash: &Sha256Hash) ->
|
|||||||
to,
|
to,
|
||||||
ref data,
|
ref data,
|
||||||
sig,
|
sig,
|
||||||
} = entry.event
|
} = *event
|
||||||
{
|
{
|
||||||
let mut sign_data = serialize(&data).unwrap();
|
let mut sign_data = serialize(&data).unwrap();
|
||||||
sign_data.extend_from_slice(&to);
|
sign_data.extend_from_slice(&to);
|
||||||
@ -210,6 +208,15 @@ pub fn verify_entry<T: Serialize>(entry: &Entry<T>, start_hash: &Sha256Hash) ->
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies self.end_hash is the result of hashing a 'start_hash' 'self.num_hashes' times.
|
||||||
|
/// If the event is not a Tick, then hash that as well.
|
||||||
|
pub fn verify_entry<T: Serialize>(entry: &Entry<T>, start_hash: &Sha256Hash) -> bool {
|
||||||
|
if !verify_event(&entry.event) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
entry.end_hash == next_hash(start_hash, entry.num_hashes, &entry.event)
|
entry.end_hash == next_hash(start_hash, entry.num_hashes, &entry.event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user