Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_shield/src/srv/msg/handshake.rs

24.4 KiB, 96 runs

created by r1870400018:4344, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1//!
2//!```ignore
3//!
4//! Handshake messages - all single-packet
5//! --------------------------------------
6//! HReq1 = first handshake request
7//! HReq2 = second handshake request
8//! HReq3 = third and final handshake request
9//! HResp1 = first handshake response
10//! HResp2 = second handshake response
11//! HResp3 = third and final handshake response
12//!
13//! PEER X PEER Y
14//! ======== ========
15//! | Sign request with: | zy is the global,
16//! | sqx = signature private key | non-specific required
17//! | In packet or meta: | number of zero bits
18//! | ax = src_addr | and is generally
19//! | ux = uid | relatively large.
20//! | Assumed or known: |
21//! | cy = code expected by y |
22//! | zy = zbits expected by y |
23//! | spy = signature public key for y |
24//! | | potentially drop
25//! "Can I start an +>>>>>>>>>>>>>>>>>>>>> HReq1 >>>>>>>>>>>>>>>>>>>|-----# based on
26//! encrypted session | | (ax, ux, cy, zy, spy)
27//! with you?" | I'm sending you: |
28//! | Plain in message: | If the packet signature
29//! | zxy = zbits expected from y | verifies, we know the
30//! | spy = last sign pub key I have for you | request is authentic.
31//! zxy ~ zy | In validation artefact: | However, we may not
32//! (i.e. relatively large) | spx = my current signature pk | recognise the public key
33//! | | spx. In this case, send X
34//! | | the spx we have, and ask
35//! | | them to sign the next
36//! | | request with it.
37//! | Sign request with: |
38//! | sqy = signature private key* | * Either current or sqy
39//! | In packet or meta: | corresponding with spy
40//! | ay = src_addr | sent by X.
41//! | uy = uid |
42//! | Using: | ** Only send if spy sent
43//! | cxy = code expected by y | by X is old.
44//! | zxy = zbits expected by y |
45//! | Optional request: |
46//! | sign HReq2 using old key |
47//! | |
48//! drop due to #------+<<<<<<<<<<<<<<<<<<<< HResp1 <<<<<<<<<<<<<<<<<<<+ "Ok, here is my
49//! (ay, uy, cy, zy)? | | authentic response."
50//! | I'm sending you: |
51//! | Plain in message: | If spy sent by X is a
52//! | cyx = code expected from x | valid old signature pk
53//! | zyx = zbits expected from x | of mine, use it to sign,
54//! | spx = your old sign pk (opt)**| but also send current
55//! | | spy.
56//! If the signature | |
57//! verifies we know the | |
58//! response is authentic. | |
59//! | Sign request with: |
60//! | sqx = old/curr sign private |
61//! | Use: |
62//! | cyx = code expected by y |
63//! | zyx = zbits expected by y |
64//! | |
65//! "Ok that looks +>>>>>>>>>>>>>>>>>>>> HReq2 >>>>>>>>>>>>>>>>>>>>|-----> drop due to
66//! authentic, I've signed | | (ax, ux, cx, zx)?
67//! this with my old | I'm sending you, if necessary: |
68//! signature if you didn't | spx = sign pub key used |
69//! recognise my current | |
70//! signature." | |
71//! | |
72//! | |
73//! | Sign request with: |
74//! | sqy = curr sign priv key | The request is authentic,
75//! | In packet or meta: | generate a KEM key pair
76//! | ay = src_addr | and send a random secret
77//! | uy = uid | session key.
78//! | Using: |
79//! | cxy = code expected by y | No change to pow reqs, yet.
80//! | zxy = zbits expected by y |
81//! | Optional request: |
82//! | |
83//! drop due to #------+<<<<<<<<<<<<<<<<<<<< HResp2 <<<<<<<<<<<<<<<<<<<+ "Great, I've used the KEM
84//! (ay, uy, cy, zy)? | | for this protocol version
85//! | I'm sending you: | to send you a secret
86//! | cyx = code expected from x | session encryption key."
87//! | zyx = zbits expected from x |
88//! | ek = session enc key (enc) | The session id is always
89//! | sid = session id, encrypted | encrypted.
90//! | |
91//! "I've encrypted a hash +>>>>>>>>>>>>>>>>>>>> HReq3 >>>>>>>>>>>>>>>>>>>>|-----> drop due to
92//! of the session id." | | (ax, ux, cx, zx)?
93//! | I'm sending you: |
94//! | H(sid) = session id, encrypted |
95//! | |
96//! | |
97//! drop due to #------+<<<<<<<<<<<<<<<<<<<< HResp3 <<<<<<<<<<<<<<<<<<<+ "Looks good, confirmed
98//! (ay, uy, cy, zy)? | | from my end, you can begin
99//! | | sending session messages."
100//! | |
101//! zxy relaxed as trust | | zyx relaxed as trust
102//! increases during | | increases during session.
103//! session. | |
104//! | |
105//! | |
106//! +>>>>>>>>>>>>>>> Protocol message >>>>>>>>>>>>>>|-----> drop due to
107//! | | (ax, ux, cx, zx)?
108//! | I'm sending you: |
109//! | cxy = updated code expected from y |
110//! | zxy = updated zbits expected from y |
111//! | |
112//! | |
113//! | |
114//! | |
115//! drop due to #------+<<<<<<<<<<<<<<< Protocol message <<<<<<<<<<<<<<+
116//! (ay, uy, cy, zy)? | |
117//! | I'm sending you: |
118//! | cyx = updated code expected |
119//! | from x |
120//! | zyx = updated zbits expected |
121//! | from x |
122//! | |
123//! | |
124//! | |
125//!
126//!```
127use crate::{
128 srv::{
129 msg::{
130 core::{
131 IdentifiedMessage,
132 IdTypes,
133 MsgType,
134 MsgFmt,
135 MsgIds,
136 MsgPow,
137 },
138 encode::ShieldCommand,
139 },
140 guard::data::AddressData,
141 },
142};
143
144use oxedyne_fe2o3_core::{
145 prelude::*,
146 byte::IntoBytes,
147 mem::Extract,
148};
149use oxedyne_fe2o3_jdat::prelude::*;
150use oxedyne_fe2o3_syntax::{
151 msg::{
152 Msg,
153 MsgCmd,
154 },
155};
156use oxedyne_fe2o3_text::string::Stringer;
157
158
159#[repr(u16)]
160#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
161pub enum HandshakeType {
162 Unknown = 0,
163 Req1 = 1,
164 Resp1 = 2,
165 Req2 = 3,
166 Resp2 = 4,
167 Req3 = 5,
168 Resp3 = 6,
169}
170
171impl From<MsgType> for HandshakeType {
172 fn from(u: MsgType) -> Self {
173 match u {
174 1 => Self::Req1,
175 2 => Self::Resp1,
176 3 => Self::Req2,
177 4 => Self::Resp2,
178 5 => Self::Req3,
179 6 => Self::Resp3,
180 _ => Self::Unknown,
181 }
182 }
183}
184
185impl HandshakeType {
186 pub fn is_hreq2(&self) -> bool {
187 match self {
188 Self::Req2 => true,
189 _ => false,
190 }
191 }
192}
193
194// HReq1 =======================================================================
195/// Initiate an encrypted session. X is the sender, Y the receiver.
196///
197/// X signs the request packet with their current signature, including the public key spx. If
198/// this fails to verify at Y, the packet will be dropped. Peers do not keep a record of all old
199/// peer keys, only the current version. If Y has no existing record of spx, X is unknown to Y
200/// and its policy regarding unknown users will determine whether the handshake continues. If
201/// the spx included by X does not match the version kept by Y, Y responds by sending the old spx
202/// and asking for an authentic signature in HReq2.
203///
204/// Y is free to set its difficulty and code requirements for incoming proofs of work. For
205/// example, required difficulty could increase quickly and significantly when the incoming
206/// request rate becomes exceptional, suggesting a possible DOS attack. Y can also distribute a
207/// new code via a side channel in such circumstances. X is likewise free to choose its own
208/// difficulty and code for the proof of work, but if Y considers these invalid, the request will
209/// be silently dropped, and the address possibly blacklisted for an incorrect code. If the code
210/// is thought to be correct, X may continue to try, but in a rate limited way otherwise the
211/// address will be blacklisted. To minimise work and retries, peers determined to connect will
212/// tend to choose a relatively high difficulty, disincentivising DOS attacks.
213#[derive(Clone, Debug, Default)]
214pub struct HReq1<
215 const ML: usize,
216 const SL: usize,
217 const UL: usize,
218 ID: IdTypes<ML, SL, UL>,
219> {
220 pub fmt: MsgFmt,
221 pub pow: MsgPow,
222 pub mid: MsgIds<SL, UL, ID::S, ID::U>,
223 // Command-specific
224 pub peer_sigpk: Option<Vec<u8>>, // Your version of my signature public key.
225}
226
227impl<
228 const ML: usize,
229 const SL: usize,
230 const UL: usize,
231 ID: IdTypes<ML, SL, UL>,
232>
233 IntoBytes for HReq1<ML, SL, UL, ID>
234{
235 fn into_bytes(self, buf: Vec<u8>) -> Outcome<Vec<u8>> {
236 res!(self.construct()).into_bytes(buf)
237 }
238}
239
240impl<
241 const ML: usize,
242 const SL: usize,
243 const UL: usize,
244 ID: IdTypes<ML, SL, UL>,
245>
246 IdentifiedMessage for HReq1<ML, SL, UL, ID>
247{
248 fn typ(&self) -> MsgType { HandshakeType::Req1 as MsgType }
249 fn name(&self) -> &'static str { "hreq1" }
250}
251
252impl<
253 const ML: usize,
254 const SL: usize,
255 const UL: usize,
256 ID: IdTypes<ML, SL, UL>,
257>
258 ShieldCommand<ML, SL, UL, ID> for HReq1<ML, SL, UL, ID>
259{
260 fn fmt(&self) -> &MsgFmt { &self.fmt }
261 fn pow(&self) -> &MsgPow { &self.pow }
262 fn mid(&self) -> &MsgIds<SL, UL, ID::S, ID::U> { &self.mid }
263 fn inc_sigpk(&self) -> bool { true }
264 fn pad_last(&self) -> bool { false }
265
266 fn construct(self) -> Outcome<Msg> {
267 let mut msg = Msg::new(self.syntax().clone()); // cloning ref
268 msg.set_encoding(*self.encoding());
269 if let Some(sid) = self.sid_opt() {
270 msg = res!(msg.add_arg_val("-s", Some(res!(sid.to_dat()))));
271 }
272 msg = res!(msg.add_arg_val("-zb", Some(dat!(self.pow_zbits()))));
273 let mut mcmd = res!(msg.new_cmd(self.name()));
274 if let Some(sigpk) = &self.peer_sigpk {
275 mcmd = res!(mcmd.add_arg_val("-yppsk", Some(dat!(sigpk.clone()))));
276 }
277 //mcmd = res!(mcmd.add_arg_val("-zb", Some(dat!(self.pow_zbits()))));
278 msg = res!(msg.add_cmd(mcmd));
279 for line in Stringer::new(fmt!("{:?}", msg)).to_lines(" ") {
280 debug!(async_log::stream(), "{}", line);
281 }
282 res!(msg.validate());
283 Ok(msg)
284 }
285
286 fn deconstruct(
287 &mut self,
288 mcmd: &mut MsgCmd,
289 )
290 -> Outcome<()>
291 {
292 self.peer_sigpk = match mcmd.get_arg_vals_mut("-yppsk") {
293 Some(vals) => Some(try_extract_dat!(vals[0].extract(), BC64)),
294 None => None,
295 };
296 //self.pow.zbits = match mcmd.get_arg_vals_mut("-zb") {
297 // Some(vals) => try_extract_dat_as!(vals[0].extract(), ZeroBits, U16),
298 // None => return Err(err!(errmsg!("HReq1: expected proof of work difficulty value."),
299 // Invalid, Input, Missing)),
300 //};
301 Ok(())
302 }
303}
304
305impl<
306 const ML: usize,
307 const SL: usize,
308 const UL: usize,
309 ID: IdTypes<ML, SL, UL>,
310>
311 HReq1<ML, SL, UL, ID>
312{
313 pub fn respond(
314 &mut self,
315 mcmd: &mut MsgCmd,
316 adata: &mut AddressData, // For pow parameters.
317 //mut udata: &mut UserData<{ constant::POW_CODE_LEN }>, // For pow parameters.
318 //ugrd: &mut UserGuard<IdDat, UserData>, // For user signing pk.
319 //// For sending HResp1.
320 //src_addr: &SocketAddr,
321 //chunker: Chunker,
322 ////pack_size: usize,
323 //src: Arc<UdpSocket>,
324 //trg_addr: &SocketAddr,
325 )
326 -> Outcome<()>
327 {
328 res!(self.deconstruct(mcmd)); // We now have all command-specific data.
329 adata.your_zbits = self.pow.zbits;
330 debug!(async_log::stream(), "Yay it worked!");
331 //// Create a fresh pow code and assign to the source address.
332 //let mut code = [0u8; constant::POW_CODE_LEN];
333 //Rand::fill_u8(&mut code);
334 //let pow_code = code.to_vec();
335 //adata.apow_code = Some(pow_code.clone());
336 //// Request transmission of signing key?
337 //let req_send_key = match ugrd.get_user_log_mut(&self.uid()) {
338 // Some(ulog) => {
339 // if ulog.data.sigpk.is_none() {
340 // ulog.data.waiting_for_sigpk = true;
341 // true
342 // } else {
343 // ulog.data.waiting_for_sigpk = false;
344 // false
345 // }
346 // },
347 // None => true,
348 //};
349 //let response = HResp1 {
350 // fmt: self.fmt().clone(),
351 // pow: self.pow().clone(),
352 // mid: self.mid().clone(),
353 // req_send_key,
354 //};
355 //debug!(async_log::stream(), "Sending hresp1: {}", res!(response.clone().construct()));
356 //response.send(
357 // src_addr,
358 // chunker,
359 // &src_sock,
360 // &trg_addr,
361 //)
362 Ok(())
363 }
364}
365
366// HResp1 ======================================================================
367#[derive(Clone, Debug, Default)]
368pub struct HResp1<
369 const ML: usize,
370 const SL: usize,
371 const UL: usize,
372 ID: IdTypes<ML, SL, UL>,
373> {
374 pub fmt: MsgFmt,
375 pub pow: MsgPow,
376 pub mid: MsgIds<SL, UL, ID::S, ID::U>,
377 // Command-specific
378 pub send_key: bool,
379}
380
381//impl_into_bytes_for_server_msg!(HResp1);
382//
383//impl IdentifiedMessage for HResp1 {
384// fn typ(&self) -> MsgType { HandshakeType::Response1 as MsgType }
385// fn name(&self) -> &'static str { "hresp1" }
386//}
387//
388//impl ShieldCommand for HResp1 {
389//
390// fn fmt(&self) -> &MsgFmt { &self.fmt }
391// fn pow(&self) -> &MsgPow { &self.pow }
392// fn mid(&self) -> &MsgIds { &self.mid }
393//
394// fn deconstruct(
395// &mut self,
396// mcmd: &mut MsgCmd,
397// )
398// -> Outcome<()>
399// {
400// self.send_key = mcmd.has_arg("-sspk");
401// self.pow_code = match mcmd.get_arg_vals_mut("-pc") {
402// Some(vals) => try_extract_dat!(vals[0].extract(), BC64),
403// None => return Err(err!(errmsg!("No proof of work code found."),
404// Invalid, Input, Missing)),
405// };
406// self.pow_zbits = match mcmd.get_arg_vals_mut("-zb") {
407// Some(vals) => try_extract_dat_as!(vals[0].extract(), pow::ZeroBits, U16),
408// None => return Err(err!(errmsg!("No proof of work zero bit value found."),
409// Invalid, Input, Missing)),
410// };
411// Ok(())
412// }
413//
414// fn construct(self) -> Outcome<Msg> {
415// let mut msg = Msg::new(self.syntax().clone()); // TODO do we have to clone here?
416// msg.set_encoding(*self.encoding());
417// msg = res!(msg.add_arg_val("-u", Some(dat!(self.uid()))));
418// let mut mcmd = res!(msg.new_cmd("hresp1"));
419// if self.send_key {
420// mcmd = res!(mcmd.add_arg("-sspk"));
421// }
422// mcmd = res!(mcmd.add_arg_val("-pc", Some(Daticle::BC64(self.pow_code))));
423// mcmd = res!(mcmd.add_arg_val("-zb", Some(dat!(self.pow_zbits))));
424// msg = res!(msg.add_cmd(mcmd));
425// res!(msg.validate());
426// Ok(msg)
427// }
428//}
429//
430//impl HResp1 {
431//
432// //pub fn client_process(
433// // &mut self,
434// // mcmd: &mut MsgCmd,
435// // mut ugrd: &mut UserGuard<IdDat, UserData>, // For user signing pk.
436// // // For sending.
437// // src_addr: SocketAddr,
438// // pack_size: usize,
439// // src_sock: &UdpSocket,
440// // trg_addr: &SocketAddr,
441// //)
442// // -> Outcome<()>
443// //{
444// // res!(self.deconstruct(mcmd)); // We now have all command-specific data.
445//
446// // Ok(())
447// //}
448//}
449//
450////// HReq2 =======================================================================
451////#[derive(Debug, Default)]
452////pub struct HReq2 {
453//// pub fmt: MsgFmt,
454//// pub mid: MsgIds,
455//// // Command-specific
456//// pub sigpk: Option<Vec<u8>>,
457////}
458////
459////impl_into_bytes_for_server_msg!(HReq2);
460////
461////impl IdentifiedMessage for HReq2 {
462//// fn typ(&self) -> MsgType { HandshakeType::Request2 as MsgType }
463//// fn name(&self) -> &'static str { "hreq2" }
464////}
465////
466////impl Message for HReq2 {}
467////
468////impl ShieldCommand for HReq2 {
469////
470//// fn fmt(&self) -> &MsgFmt { &self.fmt }
471//// fn mid(&self) -> &MsgIds { &self.mid }
472////
473//// fn construct(self) -> Outcome<Msg> {
474//// let mut msg = Msg::new(self.syntax().clone());
475//// msg.set_encoding(*self.encoding());
476//// let mut mcmd = res!(msg.new_cmd("hreq2"));
477//// mcmd = res!(mcmd.add_arg_val("-pc", Daticle::BC64(self.pow_code)));
478//// msg = res!(msg.add_cmd(mcmd));
479//// res!(msg.validate());
480//// Ok(msg)
481//// }
482////}
483////
484////impl HReq2 {
485////
486//// pub fn respond(
487//// &mut self,
488//// mcmd: &mut MsgCmd,
489//// mut adata: &mut AddressData, // For pow parameters.
490//// mut ugrd: &mut UserGuard<IdDat, UserData>, // For user signing pk.
491//// // For sending HResp1.
492//// src_addr: SocketAddr,
493//// pack_size: usize,
494//// src_sock: &UdpSocket,
495//// trg_addr: &SocketAddr,
496//// )
497//// -> Outcome<()>
498//// {
499//// res!(self.deconstruct(mcmd)); // We now have all command-specific data.
500//// let waiting_for_sigpk = match ugrd.get_user_log_mut(&self.uid()) {
501//// Some(ulog) => {
502//// if ulog.data.sigpk.is_none() {
503//// ulog.data.waiting_for_sigpk = true;
504//// true
505//// } else {
506//// ulog.data.waiting_for_sigpk = false;
507//// false
508//// }
509//// },
510//// None => true,
511//// };
512//// let mut code = [0u8; PowPristine::CODE_LEN];
513//// Rand::fill_u8(&mut code);
514//// let pow_code = code.to_vec();
515//// adata.apow_code = Some(pow_code.clone());
516//// let send_key = match ugrd.get_user_log_mut(&self.uid()) {
517//// Some(ulog) => ulog.data.sigpk.is_none(),
518//// None => true,
519//// };
520//// let response = HResp1 {
521//// fmt: self.fmt().clone(),
522//// mid: self.mid().clone(),
523//// send_key,
524//// pow_code,
525//// pow_zbits: adata.apow_zbits,
526//// };
527//// response.send(
528//// src_addr,
529//// code,
530//// adata.apow_zbits,
531//// pack_size,
532//// &src_sock,
533//// &trg_addr,
534//// )
535//// }
536////}