1#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
57#![allow(deprecated)] mod io;
60mod protocol;
61
62pub use io::Output;
63
64use crate::handshake::State;
65use crate::io::handshake;
66use crate::protocol::{noise_params_into_builder, AuthenticKeypair, Keypair, PARAMS_XX};
67use futures::prelude::*;
68use libp2p_core::{InboundUpgrade, OutboundUpgrade, UpgradeInfo};
69use libp2p_identity as identity;
70use libp2p_identity::PeerId;
71use multiaddr::Protocol;
72use multihash::Multihash;
73use snow::params::NoiseParams;
74use std::collections::HashSet;
75use std::fmt::Write;
76use std::pin::Pin;
77
78#[derive(Clone)]
80pub struct Config {
81 dh_keys: AuthenticKeypair,
82 params: NoiseParams,
83 webtransport_certhashes: Option<HashSet<Multihash<64>>>,
84
85 prologue: Vec<u8>,
92}
93
94impl Config {
95 pub fn new(identity: &identity::Keypair) -> Result<Self, Error> {
97 let noise_keys = Keypair::new().into_authentic(identity)?;
98
99 Ok(Self {
100 dh_keys: noise_keys,
101 params: PARAMS_XX.clone(),
102 webtransport_certhashes: None,
103 prologue: vec![],
104 })
105 }
106
107 pub fn with_prologue(mut self, prologue: Vec<u8>) -> Self {
109 self.prologue = prologue;
110 self
111 }
112
113 pub fn with_webtransport_certhashes(mut self, certhashes: HashSet<Multihash<64>>) -> Self {
120 self.webtransport_certhashes = Some(certhashes).filter(|h| !h.is_empty());
121 self
122 }
123
124 fn into_responder<S>(self, socket: S) -> Result<State<S>, Error> {
125 let session = noise_params_into_builder(
126 self.params,
127 &self.prologue,
128 self.dh_keys.keypair.secret(),
129 None,
130 )
131 .build_responder()?;
132
133 let state = State::new(
134 socket,
135 session,
136 self.dh_keys.identity,
137 None,
138 self.webtransport_certhashes,
139 );
140
141 Ok(state)
142 }
143
144 fn into_initiator<S>(self, socket: S) -> Result<State<S>, Error> {
145 let session = noise_params_into_builder(
146 self.params,
147 &self.prologue,
148 self.dh_keys.keypair.secret(),
149 None,
150 )
151 .build_initiator()?;
152
153 let state = State::new(
154 socket,
155 session,
156 self.dh_keys.identity,
157 None,
158 self.webtransport_certhashes,
159 );
160
161 Ok(state)
162 }
163}
164
165impl UpgradeInfo for Config {
166 type Info = &'static str;
167 type InfoIter = std::iter::Once<Self::Info>;
168
169 fn protocol_info(&self) -> Self::InfoIter {
170 std::iter::once("/noise")
171 }
172}
173
174impl<T> InboundUpgrade<T> for Config
175where
176 T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
177{
178 type Output = (PeerId, Output<T>);
179 type Error = Error;
180 type Future = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send>>;
181
182 fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future {
183 async move {
184 let mut state = self.into_responder(socket)?;
185
186 handshake::recv_empty(&mut state).await?;
187 handshake::send_identity(&mut state).await?;
188 handshake::recv_identity(&mut state).await?;
189
190 let (pk, io) = state.finish()?;
191
192 Ok((pk.to_peer_id(), io))
193 }
194 .boxed()
195 }
196}
197
198impl<T> OutboundUpgrade<T> for Config
199where
200 T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
201{
202 type Output = (PeerId, Output<T>);
203 type Error = Error;
204 type Future = Pin<Box<dyn Future<Output = Result<Self::Output, Self::Error>> + Send>>;
205
206 fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future {
207 async move {
208 let mut state = self.into_initiator(socket)?;
209
210 handshake::send_empty(&mut state).await?;
211 handshake::recv_identity(&mut state).await?;
212 handshake::send_identity(&mut state).await?;
213
214 let (pk, io) = state.finish()?;
215
216 Ok((pk.to_peer_id(), io))
217 }
218 .boxed()
219 }
220}
221
222#[derive(Debug, thiserror::Error)]
224#[non_exhaustive]
225pub enum Error {
226 #[error(transparent)]
227 Io(#[from] std::io::Error),
228 #[error(transparent)]
229 Noise(#[from] snow::Error),
230 #[error("Invalid public key")]
231 InvalidKey(#[from] libp2p_identity::DecodingError),
232 #[error("Only keys of length 32 bytes are supported")]
233 InvalidLength,
234 #[error("Remote authenticated with an unexpected public key")]
235 UnexpectedKey,
236 #[error("The signature of the remote identity's public key does not verify")]
237 BadSignature,
238 #[error("Authentication failed")]
239 AuthenticationFailed,
240 #[error("failed to decode protobuf ")]
241 InvalidPayload(#[from] DecodeError),
242 #[error(transparent)]
243 SigningError(#[from] libp2p_identity::SigningError),
244 #[error("Expected WebTransport certhashes ({}) are not a subset of received ones ({})", certhashes_to_string(.0), certhashes_to_string(.1))]
245 UnknownWebTransportCerthashes(HashSet<Multihash<64>>, HashSet<Multihash<64>>),
246}
247
248#[derive(Debug, thiserror::Error)]
249#[error(transparent)]
250pub struct DecodeError(quick_protobuf::Error);
251
252fn certhashes_to_string(certhashes: &HashSet<Multihash<64>>) -> String {
253 let mut s = String::new();
254
255 for hash in certhashes {
256 write!(&mut s, "{}", Protocol::Certhash(*hash)).unwrap();
257 }
258
259 s
260}