keynesis_network/
accept.rs

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