Oregami
Repositories/oxedyne/fe2o3

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

22.7 KiB, 107 runs

created by r1870400018:884, 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

1use crate::{
2 srv::{
3 constant,
4 msg::{
5 app::AppMsgKind,
6 core::MsgType,
7 handshake::HandshakeType,
8 },
9 },
10};
11
12use oxedyne_fe2o3_core::{
13 prelude::*,
14 byte::{
15 FromBytes,
16 ToBytes,
17 },
18};
19use oxedyne_fe2o3_iop_crypto::sign::Signer;
20use oxedyne_fe2o3_jdat::{
21 id::NumIdDat,
22 version::SemVer,
23};
24use oxedyne_fe2o3_hash::{
25 pow::{
26 PowCreateParams,
27 PowSearchResult,
28 PowVars,
29 Pristine,
30 ProofOfWork,
31 },
32};
33use oxedyne_fe2o3_iop_hash::api::Hasher;
34use oxedyne_fe2o3_namex::id::LocalId;
35
36use std::{
37 convert::TryFrom,
38 ops::Range,
39};
40
41pub type PacketCount = u32;
42pub const PACKET_COUNT_BYTE_LEN: usize = 4;
43
44/// A more economical form of `oxedyne_fe2o3_jdat::chunk::ChunkState`.
45#[derive(Clone, Debug, Default)]
46pub struct PacketChunkState {
47 pub index: PacketCount,
48 pub num_chunks: PacketCount,
49 pub chunk_size: u16,
50 pub pad_last: bool,
51}
52
53impl ToBytes for PacketChunkState {
54 fn to_bytes(&self, mut buf: Vec<u8>) -> Outcome<Vec<u8>> {
55 buf.extend_from_slice(&self.index.to_be_bytes());
56 buf.extend_from_slice(&self.num_chunks.to_be_bytes());
57 buf.extend_from_slice(&self.chunk_size.to_be_bytes());
58 buf.push(if self.pad_last { 1 } else { 0 });
59 Ok(buf)
60 }
61}
62
63impl FromBytes for PacketChunkState {
64 fn from_bytes(buf: &[u8]) -> Outcome<(Self, usize)> {
65 let mut result = Self::default();
66 if buf.len() < Self::BYTE_LEN {
67 return Err(err!(
68 "Not enough bytes to decode, require at least {}, found only {}.",
69 Self::BYTE_LEN, buf.len();
70 Bytes, Input, Decode, Missing));
71 }
72 let mut n: usize = 0;
73 result.index = PacketCount::from_be_bytes(res!(
74 <[u8; PACKET_COUNT_BYTE_LEN]>::try_from(&buf[n..n + PACKET_COUNT_BYTE_LEN]),
75 Decode, Bytes));
76 n += PACKET_COUNT_BYTE_LEN;
77
78 result.num_chunks = PacketCount::from_be_bytes(res!(
79 <[u8; PACKET_COUNT_BYTE_LEN]>::try_from(
80 &buf[n..n + PACKET_COUNT_BYTE_LEN]
81 ), Decode, Bytes));
82 n += PACKET_COUNT_BYTE_LEN;
83
84 result.chunk_size = u16::from_be_bytes(res!(
85 <[u8; 2]>::try_from(
86 &buf[n..n + 2]
87 ), Decode, Bytes));
88 n += 2;
89
90 result.pad_last = match u8::from_be_bytes(res!(
91 <[u8; 1]>::try_from(
92 &buf[n..n + 1]
93 ), Decode, Bytes)) {
94 0 => false,
95 _ => true,
96 };
97 n += 1;
98
99 Ok((result, n))
100 }
101}
102
103impl PacketChunkState {
104 pub const BYTE_LEN: usize = 2 * PACKET_COUNT_BYTE_LEN + 2 + 1;
105}
106
107#[derive(Clone, Debug)]
108pub struct PacketMeta<
109 const MIDL: usize,
110 const UIDL: usize,
111 MID: NumIdDat<MIDL>,
112 UID: NumIdDat<UIDL>,
113> {
114 pub typ: MsgType,
115 pub ver: SemVer,
116 pub mid: MID,
117 pub uid: UID,
118 pub chnk: PacketChunkState,
119}
120
121impl<
122 const MIDL: usize,
123 const UIDL: usize,
124 MID: NumIdDat<MIDL>,
125 UID: NumIdDat<UIDL>,
126>
127 Default for PacketMeta<MIDL, UIDL, MID, UID>
128{
129 fn default() -> Self {
130 Self {
131 typ: 0,
132 ver: SemVer::default(),
133 mid: MID::default(),
134 uid: UID::default(),
135 chnk: PacketChunkState::default(),
136 }
137 }
138}
139
140/// ```ignore
141///
142/// Byte map:
143///
144/// □□ □□□ □□□□□□□□ □□□□□□□□□□□□□□□□ □□□□ □□□□ □□ □□□□□□□□
145/// | | mid uid | | | tstamp
146/// typ | index | chunk_
147/// ver+ | size
148/// num_
149/// chunks
150/// \___________/
151/// |
152/// chunk state
153/// ```
154impl<
155 const MIDL: usize,
156 const UIDL: usize,
157 MID: NumIdDat<MIDL>,
158 UID: NumIdDat<UIDL>,
159>
160 ToBytes for PacketMeta<MIDL, UIDL, MID, UID>
161{
162 fn to_bytes(&self, mut buf: Vec<u8>) -> Outcome<Vec<u8>> {
163 buf.extend_from_slice(&self.typ.to_be_bytes());
164 buf = res!(self.ver.to_bytes(buf));
165 buf = res!(self.mid.to_bytes(buf));
166 buf = res!(self.uid.to_bytes(buf));
167 buf = res!(self.chnk.to_bytes(buf));
168 //buf.extend_from_slice(&self.tstamp.to_be_bytes());
169 Ok(buf)
170 }
171}
172
173impl<
174 const MIDL: usize,
175 const UIDL: usize,
176 MID: NumIdDat<MIDL>,
177 UID: NumIdDat<UIDL>,
178>
179 FromBytes for PacketMeta<MIDL, UIDL, MID, UID>
180{
181 fn from_bytes(buf: &[u8]) -> Outcome<(Self, usize)> {
182 let mut result = Self::default();
183 if buf.len() < Self::BYTE_LEN {
184 return Err(err!(
185 "Not enough bytes to decode, require at least {}, found only {}.",
186 Self::BYTE_LEN, buf.len();
187 Bytes, Input, Decode, Missing));
188 }
189
190 let mut n = constant::MSG_TYPE_BYTE_LEN;
191 result.typ = MsgType::from_be_bytes(res!(
192 <[u8; constant::MSG_TYPE_BYTE_LEN]>::try_from(&buf[0..n]),
193 Decode, Bytes)
194 );
195
196 let (ver, n2) = res!(SemVer::from_bytes(&buf[n..]));
197 result.ver = ver;
198 n += n2;
199
200 let (mid, n_mid) = res!(MID::from_bytes(&buf[n..]));
201 result.mid = mid;
202 n += n_mid;
203
204 let (uid, n_uid) = res!(UID::from_bytes(&buf[n..]));
205 result.uid = uid;
206 n += n_uid;
207
208 let (chnk, n0) = res!(PacketChunkState::from_bytes(&buf[n..]));
209 result.chnk = chnk;
210 n += n0;
211
212 Ok((result, n))
213 }
214}
215
216impl<
217 const MIDL: usize,
218 const UIDL: usize,
219 MID: NumIdDat<MIDL>,
220 UID: NumIdDat<UIDL>,
221>
222 PacketMeta<MIDL, UIDL, MID, UID>
223{
224 pub const BYTE_LEN: usize =
225 constant::MSG_TYPE_BYTE_LEN + // message type
226 SemVer::BYTE_LEN +
227 MIDL +
228 UIDL +
229 PacketChunkState::BYTE_LEN;// +
230 //8; // time since Unix epoch in seconds
231}
232
233#[repr(u8)]
234pub enum PacketValidatorId {
235 Pow = 1,
236 BareSignature = 2,
237 SignatureWithKey = 3,
238}
239
240impl TryFrom<u8> for PacketValidatorId {
241 type Error = Error<ErrTag>;
242 fn try_from(n: u8) -> std::result::Result<Self, Self::Error> {
243 match n {
244 1 => Ok(Self::Pow),
245 2 => Ok(Self::BareSignature),
246 3 => Ok(Self::SignatureWithKey),
247 _ => Err(err!(
248 "Number {} not recognised as a PacketValidatorId.", n;
249 Input, Invalid)),
250 }
251 }
252}
253
254/// Contains the optional ranges for the validation artefacts in a byte slice, including:
255/// - Proof of work artefact p0..p1,
256/// - Signature artefact s0..s1 and s2..s3, s4..s5 when the public key is included.
257#[derive(Default)]
258pub struct PacketValidationArtefactRelativeIndices {
259 pub pow: Option<Range<usize>>,
260 pub sig: Option<(Range<usize>, Option<(Range<usize>, Range<usize>)>)>,
261}
262
263///```ignore
264///
265/// Case of no public key with (bare) signature:
266///
267/// u16 len u16 len
268/// | | signature
269/// --+ --+ / artefact
270/// □□□ □□□□□□□□□□□□□□□□□□□□□□□□ □□□ □□□□□□□□
271/// | | | | | | |
272/// id | pow artefact | id | |
273/// | p0 p1 s0 s1
274/// n=0
275///
276/// Case of public key with signature:
277///
278/// u16 len u16 len u16 len
279/// u16 len artefact pub key signature
280/// | | | |
281/// --+ +-- --+ --+
282/// □□□ □□□□□□□□□□□□□□□□□□□□□□□□ □□□ □□ □□□□□□ □□ □□□□□□□□
283/// | | | | | | | | | | | |
284/// id | pow artefact | id | | | | | | |
285/// p0 p1 s0 s2 | s3 s4 | s1,s5
286/// | |
287/// signature signature
288/// public key
289///```
290impl FromBytes for PacketValidationArtefactRelativeIndices {
291 fn from_bytes(buf: &[u8]) -> Outcome<(Self, usize)> {
292 let mut result = Self::default();
293 let mut n: usize = 0;
294 match PacketValidatorId::try_from(buf[n] as u8) {
295 Ok(PacketValidatorId::Pow) => {
296 n += 1;
297 let (len, ns) = res!(Self::read_size(&buf, n));
298 n += ns;
299 result.pow = Some(n..n + len);
300 n += len;
301 },
302 _ => result.pow = None,
303 }
304 match PacketValidatorId::try_from(buf[n] as u8) {
305 Ok(pvid) => {
306 match pvid {
307 PacketValidatorId::BareSignature | PacketValidatorId::SignatureWithKey => {
308 // Get the overall artefact range.
309 n += 1;
310 let (len, ns) = res!(Self::read_size(&buf, n));
311 n += ns;
312 let sigval_rng = n..n + len;
313 //result.sig = Some(n..n + len);
314 let withkey_ranges = if let PacketValidatorId::SignatureWithKey = pvid {
315 // Get the ranges for the key and the signature.
316 let (pk_len, ns) = res!(Self::read_size(&buf, n));
317 n += ns;
318 let pk_rng = n..n + pk_len;
319 n += pk_len;
320 let (sig_len, ns) = res!(Self::read_size(&buf, n));
321 n += ns;
322 let sig_rng = n..n + sig_len;
323 n += sig_len;
324 if sigval_rng.end != sig_rng.end {
325 return Err(err!(
326 "The end point of the overall relative signature artefact range, \
327 {:?}, should match the end point of the relative range of the actual \
328 signature, {:?}, when the public key (range {:?}) is included.",
329 sigval_rng, sig_rng, pk_rng;
330 Bug, Index, Mismatch));
331 }
332 Some((pk_rng, sig_rng))
333 } else {
334 n += len;
335 None
336 };
337 result.sig = Some((sigval_rng, withkey_ranges));
338 },
339 _ => result.sig = None,
340 }
341 },
342 _ => result.sig = None,
343 }
344 Ok((result, n))
345 }
346}
347
348impl PacketValidationArtefactRelativeIndices {
349
350 pub const BYTE_PREFIX_LEN: usize = 1 + 2;
351
352 fn read_size(buf: &[u8], n: usize) -> Outcome<(usize, usize)> {
353 Ok((
354 u16::from_be_bytes(res!(<[u8; 2]>::try_from(&buf[n..n+2]),
355 Decode, Bytes)) as usize,
356 2,
357 ))
358 }
359}
360
361/// Contains the algorithmic schemes for shield packet validation.
362#[derive(Clone, Debug, Default)]
363pub struct PacketValidator<
364 // Proof of work validation.
365 H: Hasher, // Proof of work hasher.
366 // Digital signature validation.
367 S: Signer,
368> {
369 //pub pow: Option<(ProofOfWork<H>, Option<PowParams<P0, P1, PRIS>>)>,
370 pub pow: Option<ProofOfWork<H>>,
371 pub sig: Option<S>,
372}
373
374impl<
375 // Proof of work validator.
376 H: Hasher + Send + 'static, // Proof of work hasher.
377 // Digital signature validation.
378 S: Signer,
379>
380 PacketValidator<H, S>
381{
382 pub fn to_bytes<
383 const N: usize, // Pristine + Nonce size.
384 const P0: usize, // Length of pristine prefix bytes (i.e. not included in artefact).
385 const P1: usize, // Length of pristine bytes (i.e. included in artefact).
386 PRIS: Pristine<P0, P1>, // Pristine supplied to hasher.
387 >(
388 &self,
389 mut buf: Vec<u8>,
390 powparams: &PowCreateParams<P0, P1, PRIS>,
391 inc_sigpk: bool,
392 )
393 -> Outcome<Vec<u8>>
394 {
395 if let Some(power) = &self.pow {
396 match power.create::<N, P0, P1, PRIS>(powparams) {
397 Ok(PowSearchResult{
398 found,
399 mut artefact,
400 elapsed,
401 err,
402 ..
403 }) => {
404 if let Some(e) = err {
405 return Err(e);
406 }
407 if !found {
408 return Err(err!(
409 "Proof of work validator: search timed out after {:?}.",
410 elapsed;
411 Timeout, Missing));
412 }
413
414 /////// Debugging only.
415 trace!(async_log::stream(), "POW tx:");
416 res!(self.trace(
417 Some(&powparams.pvars),
418 &artefact,
419 ));
420 ///////
421
422 buf.extend_from_slice(&(PacketValidatorId::Pow as u8).to_be_bytes());
423 buf.extend_from_slice(&(artefact.len() as u16).to_be_bytes());
424 buf.append(&mut artefact);
425 },
426 Err(e) => return Err(e),
427 }
428 }
429 if let Some(signer) = &self.sig {
430 match inc_sigpk {
431 true => {
432 let mut sig = res!(signer.sign(&buf));
433 let pk = match res!(signer.get_public_key()) {
434 Some(k) => k,
435 None => return Err(err!(
436 "Signature validator: public key not available.";
437 Bug, Configuration, Missing)),
438 };
439 let mut artefact = Vec::new();
440 artefact.extend_from_slice(&(pk.len() as u16).to_be_bytes());
441 artefact.extend_from_slice(&pk[..]); // Key first..
442 artefact.extend_from_slice(&(sig.len() as u16).to_be_bytes());
443 artefact.append(&mut sig); // then signature
444
445 buf.extend_from_slice(&(PacketValidatorId::SignatureWithKey as u8).to_be_bytes());
446 buf.extend_from_slice(&(artefact.len() as u16).to_be_bytes());
447 buf.append(&mut artefact);
448 },
449 false => {
450 let mut artefact = res!(signer.sign(&buf));
451 buf.extend_from_slice(&(PacketValidatorId::BareSignature as u8).to_be_bytes());
452 buf.extend_from_slice(&(artefact.len() as u16).to_be_bytes());
453 buf.append(&mut artefact);
454 },
455 }
456 }
457 Ok(buf)
458 }
459
460 pub fn may_carry_signing_key(msg_typ: MsgType) -> bool {
461 if HandshakeType::from(msg_typ) == HandshakeType::Req1 {
462 return true;
463 }
464 AppMsgKind::from_msg_type(msg_typ).is_some()
465 }
466
467 /// The signature is based on the entire packet up to but not including the signature artefact.
468 pub fn validate<
469 const P0: usize,
470 const P1: usize,
471 PRIS: Pristine<P0, P1>,
472 >(
473 self,
474 buf: &[u8], // Entire packet.
475 n0: usize, // Start index of validation artefacts within packet.
476 afact_rel_ind: PacketValidationArtefactRelativeIndices,
477 //powvals: Option<([u8; P0], pow::ZeroBits)>, // (pristine prefix, reqd zbits)
478 powvars: Option<PowVars<P0, P1, PRIS>>,
479 msg_typ: MsgType,
480 )
481 -> Outcome<PacketValidationResult>
482 {
483 let pow = match self.pow {
484 Some(power) => {
485 let powvars = res!(powvars.ok_or(err!(
486 "Proof of work validation missing requirements.";
487 Bug, Configuration, Missing)));
488 match afact_rel_ind.pow {
489 Some(range) => {
490 Some(res!(power.validate(
491 &powvars,
492 &buf[n0 + range.start..n0 + range.end],
493 )))
494 }
495 None => return Err(err!(
496 "Proof of work validation missing artefact.";
497 Bug, Configuration, Missing)),
498 }
499 },
500 None => None,
501 };
502 let sig = match self.sig {
503 Some(mut signer) => match afact_rel_ind.sig {
504 Some((range, None)) => { // range covers only the signature.
505 let len = range.len() + PacketValidationArtefactRelativeIndices::BYTE_PREFIX_LEN;
506 Some((
507 res!(signer.verify(
508 &buf[..buf.len() - len], // Sign against everything up to the signature.
509 &buf[n0 + range.start..n0 + range.end],
510 )),
511 None,
512 ))
513 },
514 Some((range, Some((pk_rng, sig_rng)))) => { // range covers the public key and the signature.
515 // A packet may carry the key it was signed with only where the
516 // receiver could not be expected to hold one already: the handshake's
517 // opening request, and an application payload, which is outside any
518 // session and so has nothing to have exchanged a key through.
519 //
520 // Anywhere else the key is refused, and refused as a *failed*
521 // signature rather than as no signature at all. Reporting it as
522 // unchecked let a packet that carried its own key be accepted on its
523 // proof of work alone, which is to say by anybody willing to spend
524 // the work.
525 if !Self::may_carry_signing_key(msg_typ) {
526 return Ok(PacketValidationResult {
527 pow,
528 sig: Some((false, None)),
529 });
530 }
531 let len = range.len() + PacketValidationArtefactRelativeIndices::BYTE_PREFIX_LEN;
532 let pk = &buf[n0 + pk_rng.start..n0 + pk_rng.end];
533 signer = res!(signer.set_public_key(Some(&pk[..])));
534 Some((
535 res!(signer.verify(
536 &buf[..buf.len() - len], // Sign against everything up to the signature.
537 &buf[n0 + sig_rng.start..n0 + sig_rng.end],
538 )),
539 Some((signer.local_id(), pk)),
540 ))
541 },
542 None => return Err(err!(
543 "Validator requires a signature but no artefact has been included.";
544 Bug, Configuration, Missing)),
545 },
546 None => None,
547 };
548
549 Ok(PacketValidationResult {
550 pow,
551 sig,
552 })
553 }
554
555 pub fn trace<
556 const P0: usize,
557 const P1: usize,
558 PRIS: Pristine<P0, P1>,
559 >(
560 &self,
561 powvars: Option<&PowVars<P0, P1, PRIS>>,
562 artefact: &[u8],
563 )
564 -> Outcome<()>
565 {
566 match &self.pow {
567 Some(power) => {
568 match powvars {
569 Some(powvars) => {
570 let gnomon = power.hasher.hash_length();
571 let hlen = res!(gnomon.required("hash length"));
572 let alen = artefact.len();
573 let nlen = alen - hlen - (P1-P0);
574 let h_start = alen - hlen;
575 let n_start = h_start - nlen;
576 let pristine = res!(powvars.pristine.to_bytes());
577 trace!(async_log::stream(), "\nPristine [{:>4}]: {:02x?}\
578 \n Prefix [{:>4}]: {:02x?}\
579 \nArtefact [{:>4}]: {:02x?}\
580 \n Nonce [{:>4}]: {:02x?}\
581 \n Hash [{:>4}]: {:02x?}",
582 P1, pristine,
583 P0, &pristine[..P0],
584 alen, artefact,
585 nlen, &artefact[n_start..h_start],
586 hlen, &artefact[h_start..],
587 );
588 },
589 None => return Err(err!(
590 "Proof of work validation missing requirements.";
591 Bug, Configuration, Missing)),
592 }
593 },
594 None => trace!(async_log::stream(), "No proof of work hasher provided."),
595 }
596 Ok(())
597 }
598}
599
600#[derive(Debug)]
601pub struct PacketValidationResult<'a> {
602 pow: Option<bool>,
603 sig: Option<(bool, Option<(LocalId, &'a[u8])>)>, // Public signing key may have been included.
604}
605
606impl<'a> PacketValidationResult<'a> {
607 /// ```ignore
608 ///
609 /// pow
610 /// +-------+-------+-------+
611 /// | T | F | None |
612 /// +------+-------+-------+-------+
613 /// | T | T | F | T |
614 /// +------+-------+-------+-------+
615 /// sig | F | F | F | F |
616 /// +------+-------+-------+-------+
617 /// | None | T | F | None |
618 /// +------+-------+-------+-------+
619 ///
620 /// ```
621 /// Combines the proof-of-work and signature results into an overall
622 /// verdict, per the truth table above, returning the signer's local id and
623 /// public key when one was supplied. `None` means no check applied.
624 pub fn is_valid(self) -> Option<(bool, Option<(LocalId, &'a[u8])>)> {
625 match self.pow {
626 Some(pb) => match self.sig {
627 Some((sb, pk_opt)) => Some((pb && sb, pk_opt)),
628 None => Some((pb, None)),
629 },
630 None => match self.sig {
631 Some((sb, pk_opt)) => Some((sb, pk_opt)),
632 None => None,
633 },
634 }
635 }
636
637 pub fn pow_invalid(&self) -> bool {
638 match self.pow {
639 Some(b) => !b,
640 None => false,
641 }
642 }
643
644 pub fn sig_invalid(&self) -> bool {
645 match self.sig {
646 Some((b, _)) => !b,
647 None => false,
648 }
649 }
650
651 pub fn pow_state(&self) -> &'static str {
652 match self.pow {
653 Some(true) => "PASS",
654 Some(false) => "FAIL",
655 None => "NONE",
656 }
657 }
658
659 pub fn sig_state(&self) -> &'static str {
660 match self.sig {
661 Some((true, _)) => "PASS",
662 Some((false, _)) => "FAIL",
663 None => "NONE",
664 }
665 }
666
667}