/
server_binder.rs
99 lines (85 loc) · 3.31 KB
/
server_binder.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Copyright (c) 2021 MASSA LABS <info@massa.net>
use super::messages::BootstrapMessage;
use crate::error::BootstrapError;
use crate::establisher::Duplex;
use crate::settings::BOOTSTRAP_RANDOMNESS_SIZE_BYTES;
use massa_hash::hash::Hash;
use massa_hash::HASH_SIZE_BYTES;
use models::SerializeMinBEInt;
use models::{with_serialization_context, SerializeCompact};
use signature::{sign, PrivateKey, Signature, SIGNATURE_SIZE_BYTES};
use std::convert::TryInto;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
/// Bootstrap server binder
pub struct BootstrapServerBinder {
max_bootstrap_message_size: u32,
local_privkey: PrivateKey,
duplex: Duplex,
prev_sig: Option<Signature>,
}
impl BootstrapServerBinder {
/// Creates a new WriteBinder.
///
/// # Argument
/// * duplex: duplex stream.
pub fn new(duplex: Duplex, local_privkey: PrivateKey) -> Self {
let max_bootstrap_message_size =
with_serialization_context(|context| context.max_bootstrap_message_size);
BootstrapServerBinder {
max_bootstrap_message_size,
local_privkey,
duplex,
prev_sig: None,
}
}
/// Performs a handshake. Should be called after connection
/// NOT cancel-safe
pub async fn handshake(&mut self) -> Result<(), BootstrapError> {
// read randomnes, check hash
let rand_hash = {
let mut random_bytes = [0u8; BOOTSTRAP_RANDOMNESS_SIZE_BYTES];
self.duplex.read_exact(&mut random_bytes).await?;
let expected_hash = Hash::from(&random_bytes);
let mut hash_bytes = [0u8; HASH_SIZE_BYTES];
self.duplex.read_exact(&mut hash_bytes).await?;
if Hash::from_bytes(&hash_bytes)? != expected_hash {
return Err(BootstrapError::GeneralError("wrong handshake hash".into()));
}
expected_hash
};
// send signature
let sig = sign(&rand_hash, &self.local_privkey)?;
self.duplex.write_all(&sig.to_bytes()).await?;
// save prev sig
self.prev_sig = Some(sig);
Ok(())
}
/// Writes the next message. NOT cancel-safe
pub async fn send(&mut self, msg: BootstrapMessage) -> Result<(), BootstrapError> {
// serialize message
let msg_bytes = msg.to_bytes_compact()?;
let msg_len: u32 = msg_bytes.len().try_into().map_err(|e| {
BootstrapError::GeneralError(format!("bootstrap message too large to encode: {}", e))
})?;
// compute signature
let sig = {
let mut signed_data = vec![0u8; SIGNATURE_SIZE_BYTES + (msg_len as usize)];
signed_data[..SIGNATURE_SIZE_BYTES]
.clone_from_slice(&self.prev_sig.unwrap().to_bytes());
signed_data[SIGNATURE_SIZE_BYTES..].clone_from_slice(&msg_bytes);
sign(&Hash::from(&signed_data), &self.local_privkey)?
};
// send signature
self.duplex.write_all(&sig.to_bytes()).await?;
// send message length
{
let msg_len_bytes = msg_len.to_be_bytes_min(self.max_bootstrap_message_size)?;
self.duplex.write_all(&msg_len_bytes).await?;
}
// send message
self.duplex.write_all(&msg_bytes).await?;
// save prev sig
self.prev_sig = Some(sig);
Ok(())
}
}