keynesis_network/
accept.rs

1use crate::{
2    codec::handshake::{HandshakeInitialize, HandshakeResponse},
3    Handle,
4};
5use anyhow::{bail, Context as _, Result};
6use keynesis_core::{
7    hash::Blake2b,
8    key::{
9        ed25519::{self, PublicKey},
10        Dh,
11    },
12    noise::{ik::A, IK},
13};
14use rand_core::{CryptoRng, RngCore};
15use tokio::io::{AsyncRead, AsyncReadExt as _, AsyncWrite, AsyncWriteExt as _};
16
17/// accept incoming handshake
18///
19/// upon opening an ASMTP session with our node, the initiator will send
20/// the initial handshake to authenticate themselves and the responser is required
21/// to respond accordingly.
22///
23/// This object offers the necessary tooling to identify the initiator so it is
24/// possible to deny the connection early enough (see [Accepting::accept])
25pub struct Accepting<I, O, RNG, K = ed25519::SecretKey> {
26    reader: I,
27    writer: O,
28    state: IK<K, Blake2b, RNG, A>,
29}
30
31impl<I, O, K, RNG> Accepting<I, O, RNG, K>
32where
33    K: Dh,
34    RNG: CryptoRng + RngCore,
35{
36    pub(crate) fn new(rng: RNG, reader: I, writer: O) -> Self {
37        Self {
38            reader,
39            writer,
40            state: IK::new(rng, &[]),
41        }
42    }
43}
44
45impl<I, O, K, RNG> Accepting<I, O, RNG, K>
46where
47    I: AsyncRead + Unpin,
48    O: AsyncWrite + Unpin,
49    K: Dh,
50    RNG: CryptoRng + RngCore,
51{
52    /// perform the initial handshake with the peer
53    ///
54    /// Upon receiving the initial handshake message, the function `check_id` will
55    /// verify the public key of the user. For example the user can maintain a list
56    /// of unwelcome public keys.
57    ///
58    /// If the peer is accepted and is using a supported version of the protocol
59    /// then the functions replies the response handshake.
60    ///
61    /// # Errors
62    ///
63    /// This function may fail for IO operations as well as for processing the
64    /// noise handshake.
65    ///
66    pub async fn accept<F>(self, k: &K, check_id: F) -> Result<Handle<I, O>>
67    where
68        F: Fn(&PublicKey) -> bool,
69    {
70        let Self {
71            mut reader,
72            mut writer,
73            state,
74        } = self;
75
76        let mut bytes = [0; HandshakeInitialize::SIZE];
77
78        reader
79            .read_exact(&mut bytes)
80            .await
81            .context("Cannot receive the Noise IK initiate Handshake")?;
82
83        let message = HandshakeInitialize::from_bytes(bytes);
84
85        if !message.version().is_supported() {
86            bail!("Unsupported version {:?}", message.version());
87        }
88
89        let state = state
90            .receive(k, message.message())
91            .context("Noise IK Handshake Initiate failed")?;
92
93        if !check_id(state.remote_public_identity()) {
94            bail!(
95                "Rejecting connection with {}",
96                state.remote_public_identity()
97            )
98        }
99
100        let mut message = HandshakeResponse::DEFAULT;
101
102        let state = state
103            .reply(&mut message.message_mut())
104            .context("Cannot prep the Noise's Handshake Response message")?;
105
106        writer
107            .write_all(message.as_ref())
108            .await
109            .context("Cannot send the Noise IK response Handshake")?;
110
111        Ok(Handle::new(reader, writer, state))
112    }
113}