libp2p_noise/io/
handshake.rs1mod proto {
24 #![allow(unreachable_pub)]
25 include!("../generated/mod.rs");
26 pub use self::payload::proto::NoiseExtensions;
27 pub use self::payload::proto::NoiseHandshakePayload;
28}
29
30use crate::io::{framed::NoiseFramed, Output};
31use crate::protocol::{KeypairIdentity, STATIC_KEY_DOMAIN};
32use crate::{DecodeError, Error};
33use bytes::Bytes;
34use futures::prelude::*;
35use libp2p_identity as identity;
36use multihash::Multihash;
37use quick_protobuf::{BytesReader, MessageRead, MessageWrite, Writer};
38use std::collections::HashSet;
39use std::io;
40
41pub(crate) struct State<T> {
46 io: NoiseFramed<T, snow::HandshakeState>,
48 identity: KeypairIdentity,
51 dh_remote_pubkey_sig: Option<Vec<u8>>,
53 id_remote_pubkey: Option<identity::PublicKey>,
55 responder_webtransport_certhashes: Option<HashSet<Multihash<64>>>,
57 remote_extensions: Option<Extensions>,
59}
60
61struct Extensions {
63 webtransport_certhashes: HashSet<Multihash<64>>,
64}
65
66impl<T> State<T> {
67 pub(crate) fn new(
74 io: T,
75 session: snow::HandshakeState,
76 identity: KeypairIdentity,
77 expected_remote_key: Option<identity::PublicKey>,
78 responder_webtransport_certhashes: Option<HashSet<Multihash<64>>>,
79 ) -> Self {
80 Self {
81 identity,
82 io: NoiseFramed::new(io, session),
83 dh_remote_pubkey_sig: None,
84 id_remote_pubkey: expected_remote_key,
85 responder_webtransport_certhashes,
86 remote_extensions: None,
87 }
88 }
89}
90
91impl<T> State<T> {
92 pub(crate) fn finish(self) -> Result<(identity::PublicKey, Output<T>), Error> {
95 let is_initiator = self.io.is_initiator();
96 let (pubkey, io) = self.io.into_transport()?;
97
98 let id_pk = self
99 .id_remote_pubkey
100 .ok_or_else(|| Error::AuthenticationFailed)?;
101
102 let is_valid_signature = self.dh_remote_pubkey_sig.as_ref().map_or(false, |s| {
103 id_pk.verify(&[STATIC_KEY_DOMAIN.as_bytes(), pubkey.as_ref()].concat(), s)
104 });
105
106 if !is_valid_signature {
107 return Err(Error::BadSignature);
108 }
109
110 if is_initiator {
112 if let Some(expected_certhashes) = self.responder_webtransport_certhashes {
114 let ext = self.remote_extensions.ok_or_else(|| {
115 Error::UnknownWebTransportCerthashes(
116 expected_certhashes.to_owned(),
117 HashSet::new(),
118 )
119 })?;
120
121 let received_certhashes = ext.webtransport_certhashes;
122
123 if !expected_certhashes.is_subset(&received_certhashes) {
126 return Err(Error::UnknownWebTransportCerthashes(
127 expected_certhashes,
128 received_certhashes,
129 ));
130 }
131 }
132 }
133
134 Ok((id_pk, io))
135 }
136}
137
138impl From<proto::NoiseExtensions> for Extensions {
139 fn from(value: proto::NoiseExtensions) -> Self {
140 Extensions {
141 webtransport_certhashes: value
142 .webtransport_certhashes
143 .into_iter()
144 .filter_map(|bytes| Multihash::read(&bytes[..]).ok())
145 .collect(),
146 }
147 }
148}
149
150async fn recv<T>(state: &mut State<T>) -> Result<Bytes, Error>
155where
156 T: AsyncRead + Unpin,
157{
158 match state.io.next().await {
159 None => Err(io::Error::new(io::ErrorKind::UnexpectedEof, "eof").into()),
160 Some(Err(e)) => Err(e.into()),
161 Some(Ok(m)) => Ok(m),
162 }
163}
164
165pub(crate) async fn recv_empty<T>(state: &mut State<T>) -> Result<(), Error>
167where
168 T: AsyncRead + Unpin,
169{
170 let msg = recv(state).await?;
171 if !msg.is_empty() {
172 return Err(
173 io::Error::new(io::ErrorKind::InvalidData, "Unexpected handshake payload.").into(),
174 );
175 }
176 Ok(())
177}
178
179pub(crate) async fn send_empty<T>(state: &mut State<T>) -> Result<(), Error>
181where
182 T: AsyncWrite + Unpin,
183{
184 state.io.send(&Vec::new()).await?;
185 Ok(())
186}
187
188pub(crate) async fn recv_identity<T>(state: &mut State<T>) -> Result<(), Error>
190where
191 T: AsyncRead + Unpin,
192{
193 let msg = recv(state).await?;
194 let mut reader = BytesReader::from_bytes(&msg[..]);
195 let pb =
196 proto::NoiseHandshakePayload::from_reader(&mut reader, &msg[..]).map_err(DecodeError)?;
197
198 state.id_remote_pubkey = Some(identity::PublicKey::try_decode_protobuf(&pb.identity_key)?);
199
200 if !pb.identity_sig.is_empty() {
201 state.dh_remote_pubkey_sig = Some(pb.identity_sig);
202 }
203
204 if let Some(extensions) = pb.extensions {
205 state.remote_extensions = Some(extensions.into());
206 }
207
208 Ok(())
209}
210
211pub(crate) async fn send_identity<T>(state: &mut State<T>) -> Result<(), Error>
213where
214 T: AsyncWrite + Unpin,
215{
216 let mut pb = proto::NoiseHandshakePayload {
217 identity_key: state.identity.public.encode_protobuf(),
218 ..Default::default()
219 };
220
221 pb.identity_sig = state.identity.signature.clone();
222
223 if state.io.is_responder() {
225 if let Some(ref certhashes) = state.responder_webtransport_certhashes {
226 let ext = pb
227 .extensions
228 .get_or_insert_with(proto::NoiseExtensions::default);
229
230 ext.webtransport_certhashes = certhashes.iter().map(|hash| hash.to_bytes()).collect();
231 }
232 }
233
234 let mut msg = Vec::with_capacity(pb.get_size());
235
236 let mut writer = Writer::new(&mut msg);
237 pb.write_message(&mut writer).expect("Encoding to succeed");
238 state.io.send(&msg).await?;
239
240 Ok(())
241}