#![doc(html_favicon_url = "https://docs.sequoia-pgp.org/favicon.png")]
#![doc(html_logo_url = "https://docs.sequoia-pgp.org/logo.svg")]
#![warn(missing_docs)]
#[cfg(test)]
#[macro_use]
extern crate quickcheck;
#[macro_use]
mod macros;
fn vec_truncate(v: &mut Vec<u8>, len: usize) {
if cfg!(debug_assertions) {
if len < v.len() {
unsafe { v.set_len(len); }
}
} else {
v.truncate(len);
}
}
fn vec_resize(v: &mut Vec<u8>, new_size: usize) {
if v.len() < new_size {
v.resize(new_size, 0);
} else {
vec_truncate(v, new_size);
}
}
fn vec_drain_prefix(v: &mut Vec<u8>, prefix_len: usize) {
if cfg!(debug_assertions) {
assert!(prefix_len <= v.len(), "prefix len {} > vector len {}",
prefix_len, v.len());
let new_len = v.len() - prefix_len;
unsafe {
std::ptr::copy(v[prefix_len..].as_ptr(),
v[..].as_mut_ptr(),
new_len);
}
vec_truncate(v, new_len);
} else {
v.drain(..prefix_len);
}
}
fn now() -> std::time::SystemTime {
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))] {
chrono::Utc::now().into()
}
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] {
std::time::SystemTime::now()
}
}
#[allow(unused_macros)]
macro_rules! assert_match {
( $error: pat = $expr:expr, $fmt:expr, $($pargs:expr),* ) => {{
let x = $expr;
if let $error = x {
} else {
let extra = format!($fmt, $($pargs),*);
panic!("Expected {}, got {:?}{}{}",
stringify!($error), x,
if $fmt.len() > 0 { ": " } else { "." }, extra);
}
}};
( $error: pat = $expr: expr, $fmt:expr ) => {
assert_match!($error = $expr, $fmt, )
};
( $error: pat = $expr: expr ) => {
assert_match!($error = $expr, "")
};
}
#[macro_use]
pub mod armor;
pub mod fmt;
pub mod crypto;
pub mod packet;
#[doc(inline)]
pub use packet::Packet;
use crate::packet::key;
pub mod parse;
pub mod cert;
#[doc(inline)]
pub use cert::Cert;
pub mod serialize;
mod packet_pile;
pub use packet_pile::PacketPile;
pub mod message;
#[doc(inline)]
pub use message::Message;
pub mod types;
use crate::types::{
PublicKeyAlgorithm,
SymmetricAlgorithm,
HashAlgorithm,
SignatureType,
};
mod fingerprint;
pub use fingerprint::Fingerprint;
mod keyid;
pub use keyid::KeyID;
mod keyhandle;
pub use keyhandle::KeyHandle;
pub mod regex;
pub mod policy;
pub(crate) mod seal;
pub(crate) mod utils;
#[cfg(test)]
mod tests;
#[cfg(test)]
fn frozen_time() -> std::time::SystemTime {
crate::types::Timestamp::from(1554542220 - 1).into()
}
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub type Result<T> = ::std::result::Result<T, anyhow::Error>;
#[non_exhaustive]
#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
pub enum Error {
#[error("Invalid argument: {0}")]
InvalidArgument(String),
#[error("Invalid operation: {0}")]
InvalidOperation(String),
#[error("Malformed packet: {0}")]
MalformedPacket(String),
#[error("{} Packet ({} bytes) exceeds limit of {} bytes",
_0, _1, _2)]
PacketTooLarge(packet::Tag, u32, u32),
#[error("Unsupported packet type. Tag: {0}")]
UnsupportedPacketType(packet::Tag),
#[error("Unsupported hash algorithm: {0}")]
UnsupportedHashAlgorithm(HashAlgorithm),
#[error("Unsupported public key algorithm: {0}")]
UnsupportedPublicKeyAlgorithm(PublicKeyAlgorithm),
#[error("Unsupported elliptic curve: {0}")]
UnsupportedEllipticCurve(types::Curve),
#[error("Unsupported symmetric algorithm: {0}")]
UnsupportedSymmetricAlgorithm(SymmetricAlgorithm),
#[error("Unsupported AEAD algorithm: {0}")]
UnsupportedAEADAlgorithm(types::AEADAlgorithm),
#[error("Unsupported Compression algorithm: {0}")]
UnsupportedCompressionAlgorithm(types::CompressionAlgorithm),
#[error("Unsupported signature type: {0}")]
UnsupportedSignatureType(SignatureType),
#[error("Invalid password")]
InvalidPassword,
#[error("Invalid session key: {0}")]
InvalidSessionKey(String),
#[error("Missing session key: {0}")]
MissingSessionKey(String),
#[error("Malformed MPI: {0}")]
MalformedMPI(String),
#[error("Bad signature: {0}")]
BadSignature(String),
#[error("Message has been manipulated")]
ManipulatedMessage,
#[error("Malformed Message: {0}")]
MalformedMessage(String),
#[error("Malformed Cert: {0}")]
MalformedCert(String),
#[error("Unsupported Cert: {0}")]
UnsupportedCert2(String, Vec<Packet>),
#[deprecated(since = "1.10.0", note = "Use UnsupportedCert2 instead.")]
#[error("Unsupported Cert: {0}")]
UnsupportedCert(String),
#[error("Index out of range")]
IndexOutOfRange,
#[error("Expired on {}", crate::fmt::time(.0))]
Expired(std::time::SystemTime),
#[error("Not live until {}", crate::fmt::time(.0))]
NotYetLive(std::time::SystemTime),
#[error("No binding signature at time {}", crate::fmt::time(.0))]
NoBindingSignature(std::time::SystemTime),
#[error("Invalid key: {0:?}")]
InvalidKey(String),
#[error("No acceptable hash")]
NoAcceptableHash,
#[error("{0} is not considered secure{}",
.1.as_ref().map(|t| {
if *t == std::time::UNIX_EPOCH {
"".to_string()
} else {
format!(" since {}", crate::fmt::time(t))
}
})
.unwrap_or_else(|| "".into()))]
PolicyViolation(String, Option<std::time::SystemTime>),
#[error("Short key IDs are insecure, and not supported: {0}")]
ShortKeyID(String),
}
assert_send_and_sync!(Error);
#[cfg(test)]
mod arbitrary_helper {
use quickcheck::{Arbitrary, Gen};
pub(crate) fn gen_arbitrary_from_range<T>(
range: std::ops::Range<T>,
g: &mut Gen,
) -> T
where
T: Arbitrary
+ std::cmp::PartialOrd
+ std::ops::Sub<Output = T>
+ std::ops::Rem<Output = T>
+ std::ops::Add<Output = T>
+ Copy,
{
if !range.is_empty() {
let m = range.end - range.start;
range.start + (T::arbitrary(g) % m + m) % m
} else {
panic!()
}
}
pub(crate) fn arbitrary_slice<T>(g: &mut Gen, s: &mut [T])
where
T: Arbitrary,
{
s.iter_mut().for_each(|p| *p = Arbitrary::arbitrary(g));
}
pub(crate) fn arbitrary_bounded_vec<T>(g: &mut Gen, limit: usize) -> Vec<T>
where
T: Arbitrary + Default,
{
let mut v = vec![Default::default();
gen_arbitrary_from_range(0..limit, g)];
arbitrary_slice(g, &mut v[..]);
v
}
}