use crate::{
Error,
Result,
};
use crate::packet::tag::Tag;
mod ctb;
pub use self::ctb::{
CTB,
CTBOld,
CTBNew,
PacketLengthType,
};
#[derive(Clone, Debug)]
pub struct Header {
ctb: CTB,
length: BodyLength,
}
assert_send_and_sync!(Header);
impl Header {
pub fn new(ctb: CTB, length: BodyLength) -> Self {
Header { ctb, length }
}
pub fn ctb(&self) -> &CTB {
&self.ctb
}
pub fn length(&self) -> &BodyLength {
&self.length
}
pub fn valid(&self, future_compatible: bool) -> Result<()> {
let tag = self.ctb.tag();
match tag {
Tag::Reserved =>
return Err(Error::UnsupportedPacketType(tag).into()),
Tag::Unknown(_) | Tag::Private(_) if !future_compatible =>
return Err(Error::UnsupportedPacketType(tag).into()),
_ => (),
}
if tag == Tag::Literal || tag == Tag::CompressedData
|| tag == Tag::SED || tag == Tag::SEIP
|| tag == Tag::AED
{
match self.length {
BodyLength::Indeterminate => (),
BodyLength::Partial(l) => {
if l < 512 {
return Err(Error::MalformedPacket(
format!("Partial body length must be \
at least 512 (got: {})",
l)).into());
}
}
BodyLength::Full(l) => {
if tag == Tag::SED && (l < (8 + 2 + 6)) { return Err(Error::MalformedPacket(
format!("{} packet's length must be \
at least 16 bytes in length (got: {})",
tag, l)).into());
} else if tag == Tag::SEIP
&& (l < (1 + 8 + 2 + 6 + 20)) {
return Err(Error::MalformedPacket(
format!("{} packet's length minus 1 must be \
at least 37 bytes in length (got: {})",
tag, l)).into());
} else if tag == Tag::CompressedData && l == 0 {
return Err(Error::MalformedPacket(
format!("{} packet's length must be \
at least 1 byte (got ({})",
tag, l)).into());
} else if tag == Tag::Literal && l < 6 {
return Err(Error::MalformedPacket(
format!("{} packet's length must be \
at least 6 bytes (got: ({})",
tag, l)).into());
}
}
}
} else {
match self.length {
BodyLength::Indeterminate =>
return Err(Error::MalformedPacket(
format!("Indeterminite length encoding \
not allowed for {} packets",
tag)).into()),
BodyLength::Partial(_) =>
return Err(Error::MalformedPacket(
format!("Partial Body Chunking not allowed \
for {} packets",
tag)).into()),
BodyLength::Full(l) => {
let valid = match tag {
Tag::Signature =>
10 <= l
&& l < (10 + 2 * 64 * 1024 + 64 * 1024 ),
Tag::SKESK =>
3 <= l && l < 10 * 1024,
Tag::PKESK =>
10 < l && l < 10 * 1024,
Tag::OnePassSig if ! future_compatible => l == 13,
Tag::OnePassSig => l < 1024,
Tag::PublicKey | Tag::PublicSubkey
| Tag::SecretKey | Tag::SecretSubkey =>
6 < l && l < 1024 * 1024,
Tag::Trust => true,
Tag::UserID =>
l < 32 * 1024,
Tag::UserAttribute =>
2 <= l,
Tag::MDC => l == 20,
Tag::Literal | Tag::CompressedData
| Tag::SED | Tag::SEIP | Tag::AED =>
unreachable!("handled in the data-packet branch"),
Tag::Unknown(_) | Tag::Private(_) => true,
Tag::Marker => l == 3,
Tag::Reserved => true,
};
if ! valid {
return Err(Error::MalformedPacket(
format!("Invalid size ({} bytes) for a {} packet",
l, tag)).into())
}
}
}
}
Ok(())
}
}
#[derive(Debug)]
#[derive(PartialEq)]
#[derive(Clone, Copy)]
pub enum BodyLength {
Full(u32),
Partial(u32),
Indeterminate,
}
assert_send_and_sync!(BodyLength);