1use std::{
2 hash::{Hash, Hasher},
3 sync::Arc,
4};
5
6use bytes::{Buf, BytesMut};
7
8use quinn_proto::{
9 ConnectionId, Side, TransportError,
10 crypto::{self, CryptoError, HeaderKey},
11 transport_parameters,
12};
13use seahash::SeaHasher;
14use tracing::{error, trace};
15
16pub fn server_config() -> quinn_proto::ServerConfig {
24 quinn_proto::ServerConfig::with_crypto(Arc::new(PlaintextServerConfig::new()))
25}
26
27pub fn client_config() -> quinn_proto::ClientConfig {
36 quinn_proto::ClientConfig::new(Arc::new(PlaintextClientConfig::new()))
37}
38
39pub struct PlaintextHeaderKey {
40 side: Side,
41}
42
43impl PlaintextHeaderKey {
44 pub fn new(side: Side) -> Self {
45 Self { side }
46 }
47}
48
49impl HeaderKey for PlaintextHeaderKey {
50 fn decrypt(&self, pn_offset: usize, packet: &mut [u8]) {
51 trace!(side = ?self.side, "HeaderKey::decrypt pn_offset: {pn_offset}");
52 trace!(side = ?self.side, "packet: {packet:?}");
53 }
55
56 fn encrypt(&self, pn_offset: usize, packet: &mut [u8]) {
57 trace!(side = ?self.side, "HeaderKey::encrypt pn_offset: {pn_offset}");
58 trace!(side = ?self.side, "packet: {packet:?}");
59 }
61
62 fn sample_size(&self) -> usize {
63 trace!(side = ?self.side, "HeaderKey::sample_size");
64 0
65 }
66}
67
68pub struct PlaintextPacketKey {
69 side: Side,
70}
71
72impl PlaintextPacketKey {
73 fn new(side: Side) -> Self {
74 Self { side }
75 }
76}
77
78#[derive(Default)]
79pub struct PlaintextClientConfig;
80
81impl PlaintextClientConfig {
82 pub fn new() -> Self {
83 Self
84 }
85}
86
87#[derive(Default)]
88pub struct PlaintextServerConfig;
89
90impl PlaintextServerConfig {
91 pub fn new() -> Self {
92 Self
93 }
94}
95
96fn crypto_keys(side: Side) -> crypto::Keys {
97 crypto::Keys {
98 header: crypto_header_keypair(side),
99 packet: crypto_packet_keypair(side),
100 }
101}
102
103fn crypto_header_keypair(side: Side) -> crypto::KeyPair<Box<dyn crypto::HeaderKey>> {
104 crypto::KeyPair {
105 local: Box::new(PlaintextHeaderKey::new(side)),
106 remote: Box::new(PlaintextHeaderKey::new(side)),
107 }
108}
109
110fn crypto_packet_keypair(side: Side) -> crypto::KeyPair<Box<dyn crypto::PacketKey>> {
111 crypto::KeyPair {
112 local: Box::new(PlaintextPacketKey::new(side)),
113 remote: Box::new(PlaintextPacketKey::new(side)),
114 }
115}
116
117pub struct PlaintextSession {
119 side: Side,
120 params: transport_parameters::TransportParameters,
121 peer_params: Option<transport_parameters::TransportParameters>,
122 wrote_transporter_params: bool,
123 initial_keys: Option<crypto::Keys>,
124 handshake_keys: Option<crypto::Keys>,
125}
126
127impl PlaintextSession {
128 fn new(side: Side, params: transport_parameters::TransportParameters) -> Self {
129 Self {
130 side,
131 params,
132 peer_params: None,
133 wrote_transporter_params: false,
134 initial_keys: Some(crypto_keys(side)),
135 handshake_keys: Some(crypto_keys(side)),
136 }
137 }
138}
139
140impl crypto::Session for PlaintextSession {
142 fn initial_keys(&self, dst_cid: &ConnectionId, _side: Side) -> crypto::Keys {
143 trace!(side = ?self.side, "initial_keys dst_cid: {dst_cid}");
144 crypto_keys(self.side)
145 }
146
147 fn handshake_data(&self) -> Option<Box<dyn std::any::Any>> {
148 trace!(side = ?self.side, "handshake_data");
149 self.peer_params
150 .map(|tp| Box::new(tp) as Box<dyn std::any::Any>)
151 }
152
153 fn peer_identity(&self) -> Option<Box<dyn std::any::Any>> {
154 trace!(side = ?self.side, "peer_identity");
155 None
156 }
157
158 fn early_crypto(&self) -> Option<(Box<dyn crypto::HeaderKey>, Box<dyn crypto::PacketKey>)> {
159 trace!(side = ?self.side, "early_crypto");
160 None
161 }
162
163 fn early_data_accepted(&self) -> Option<bool> {
164 trace!(side = ?self.side, "early_data_accepted");
165 Some(false)
166 }
167
168 fn is_handshaking(&self) -> bool {
169 trace!(side = ?self.side, "is_handshaking");
170 self.peer_params.is_none()
171 || !self.wrote_transporter_params
172 && (self.initial_keys.is_some() || self.handshake_keys.is_some())
173 }
174
175 fn read_handshake(&mut self, mut buf: &[u8]) -> Result<bool, TransportError> {
176 trace!(side = ?self.side, "read_handshake {buf:?}");
177
178 if self.peer_params.is_none() {
179 self.peer_params = Some(
180 transport_parameters::TransportParameters::read(self.side, &mut buf)
181 .expect("could not read shit"),
182 );
183 }
184 Ok(true)
185 }
186
187 fn transport_parameters(
188 &self,
189 ) -> Result<Option<transport_parameters::TransportParameters>, TransportError> {
190 trace!(side = ?self.side, "transport_parameters");
191 Ok(self.peer_params)
192 }
193
194 fn write_handshake(&mut self, buf: &mut Vec<u8>) -> Option<crypto::Keys> {
195 if self.side.is_client() && !self.wrote_transporter_params {
196 self.params.write(buf);
197 self.wrote_transporter_params = true;
198 trace!("wrote data: {buf:?}");
199 }
200
201 trace!(side = ?self.side, "write_handshake");
202
203 match self.initial_keys.take().or_else(|| {
204 self.handshake_keys.take().inspect(|_k| {
205 if self.side.is_server() && !self.wrote_transporter_params {
206 self.params.write(buf);
207 self.wrote_transporter_params = true;
208 trace!("wrote data: {buf:?}");
209 }
210 trace!("taking handshake keys");
211 })
212 }) {
213 Some(k) => Some(k),
214 None => {
215 trace!("returning None");
216 None
217 }
218 }
219 }
220
221 fn next_1rtt_keys(&mut self) -> Option<crypto::KeyPair<Box<dyn crypto::PacketKey>>> {
222 trace!(side = ?self.side, "next_1rtt_keys");
223 Some(crypto_packet_keypair(self.side))
224 }
225
226 fn is_valid_retry(&self, orig_dst_cid: &ConnectionId, _header: &[u8], _payload: &[u8]) -> bool {
227 trace!(side = ?self.side, "is_valid_retry orig_dst_cid: {orig_dst_cid}");
228 true
229 }
230
231 fn export_keying_material(
232 &self,
233 _output: &mut [u8],
234 _label: &[u8],
235 _context: &[u8],
236 ) -> Result<(), crypto::ExportKeyingMaterialError> {
237 trace!(side = ?self.side, "export_keying_material");
238 Ok(())
239 }
240}
241
242impl crypto::ClientConfig for PlaintextClientConfig {
243 fn start_session(
244 self: std::sync::Arc<Self>,
245 version: u32,
246 server_name: &str,
247 params: &transport_parameters::TransportParameters,
248 ) -> Result<Box<dyn crypto::Session>, quinn_proto::ConnectError> {
249 trace!(
250 "ClientConfig::start_session version: {version}, server_name: {server_name}, params: {params:?}"
251 );
252 Ok(Box::new(PlaintextSession::new(Side::Client, *params)))
253 }
254}
255
256impl crypto::ServerConfig for PlaintextServerConfig {
257 fn initial_keys(
258 &self,
259 version: u32,
260 dst_cid: &ConnectionId,
261 ) -> Result<crypto::Keys, crypto::UnsupportedVersion> {
262 trace!("ServerConfig::initial_keys version: {version}, dst_cid: {dst_cid:?}");
263 Ok(crypto_keys(Side::Server))
264 }
265
266 fn retry_tag(&self, version: u32, orig_dst_cid: &ConnectionId, packet: &[u8]) -> [u8; 16] {
267 trace!(
268 "ServerConfig::retry_tag version: {version}, orig_dst_cid: {orig_dst_cid:?}, packet: {packet:?}"
269 );
270
271 [0u8; 16]
272 }
273
274 fn start_session(
275 self: Arc<Self>,
276 version: u32,
277 params: &transport_parameters::TransportParameters,
278 ) -> Box<dyn crypto::Session> {
279 trace!("ServerConfig::start_session version: {version}, params: {params:?}");
280 Box::new(PlaintextSession::new(Side::Server, *params))
281 }
282}
283
284impl crypto::PacketKey for PlaintextPacketKey {
286 fn encrypt(&self, packet: u64, buf: &mut [u8], header_len: usize) {
287 trace!(side = ?self.side, "PacketKey::encrypt packet: {packet}, header_len: {header_len}");
288 let (header, payload_tag) = buf.split_at_mut(header_len);
289 trace!(side = ?self.side, "header: {header:?}");
290 trace!(side = ?self.side, "payload_tag: {payload_tag:?}");
291 let (payload, tag_storage) = payload_tag.split_at_mut(payload_tag.len() - self.tag_len());
292 trace!("tag_storage: {tag_storage:?}");
293 let mut hasher = SeaHasher::default();
294 header.hash(&mut hasher);
295 payload.hash(&mut hasher);
296 let checksum = hasher.finish();
297 trace!("checksum: {checksum:?}");
298 tag_storage.copy_from_slice(&checksum.to_be_bytes());
299 trace!("tag_storage (after put): {tag_storage:?}");
300 }
302
303 fn decrypt(
304 &self,
305 packet: u64,
306 header: &[u8],
307 payload: &mut BytesMut,
308 ) -> Result<(), CryptoError> {
309 trace!(side = ?self.side, "PacketKey::decrypt packet: {packet}, header: {header:?}");
310
311 let mut tag_storage = payload.split_off(payload.len() - self.tag_len());
312
313 trace!(side = ?self.side, "payload: {:?}", payload.as_ref());
314 trace!(side = ?self.side, "tag_storage: {:?}", tag_storage.as_ref());
315
316 let mut hasher = SeaHasher::default();
317 header.hash(&mut hasher);
318 payload.hash(&mut hasher);
319 let checksum = hasher.finish();
320
321 let expected = tag_storage.get_u64();
322 if checksum != expected {
323 error!(side = ?self.side, "checksum mismatch, expected {expected}, got: {checksum}");
324 return Err(CryptoError);
325 }
326
327 Ok(())
329 }
330
331 fn tag_len(&self) -> usize {
332 trace!(side = ?self.side, "PacketKey::tag_len");
333 8
334 }
335
336 fn confidentiality_limit(&self) -> u64 {
337 trace!(side = ?self.side, "PacketKey::confidentiality_limit");
338 u64::MAX
339 }
340
341 fn integrity_limit(&self) -> u64 {
342 trace!(side = ?self.side, "PacketKey::integrity_limit");
343 1 << 36
344 }
345}
346
347#[cfg(test)]
348mod tests {
349 use super::*;
350
351 #[tokio::test]
352 async fn basic_test() {
353 _ = tracing_subscriber::fmt::try_init();
354
355 let server_config =
356 quinn::ServerConfig::with_crypto(Arc::new(PlaintextServerConfig::new()));
357 let server = quinn::Endpoint::server(server_config, "127.0.0.1:0".parse().unwrap())
358 .expect("could not create endpoint server");
359
360 let addr = server
361 .local_addr()
362 .expect("could not get server local addr");
363
364 let test_data = b"hello world";
365
366 let server_fut = async move {
367 println!("server waiting to accept...");
368 let incoming = server.accept().await.expect("did not accept a conn!");
369 println!("accepted: {incoming:?}");
370 let connecting = incoming
371 .accept()
372 .expect("could not accept incoming connection");
373 let conn = connecting
374 .await
375 .expect("could not complete connection accept");
376
377 println!("completed accept: {conn:?}");
378
379 let mut recv = conn
380 .accept_uni()
381 .await
382 .expect("could not accept uni stream");
383
384 println!("ACCEPTED UNI STREAM");
385
386 let mut b = vec![0u8; test_data.len()];
387 recv.read_exact(&mut b)
388 .await
389 .expect("could not test string");
390
391 b
392 };
393
394 let client_fut = async move {
395 let client_config = quinn::ClientConfig::new(Arc::new(PlaintextClientConfig::new()));
396 let client = quinn::Endpoint::client("127.0.0.1:0".parse().unwrap())
397 .expect("could not create endpoint client");
398
399 let conn = client
400 .connect_with(client_config, addr, "plaintext.test")
401 .expect("could not create connection future")
402 .await
403 .expect("could not connect to server");
404
405 println!("OPENING UNI STREAM");
406
407 let mut send = conn.open_uni().await.unwrap();
408
409 println!("opened a unidirectional stream");
410
411 send.write_all(b"hello world").await.unwrap();
412
413 tokio::time::sleep(std::time::Duration::from_millis(10)).await;
415
416 send.finish().unwrap();
417 };
418
419 let (buf, _) = tokio::join!(server_fut, client_fut);
420
421 assert_eq!(buf, test_data);
422 }
423}