use std::io;
use std::mem;
use std::vec;
use buffered_reader::BufferedReader;
use lalrpop_util::ParseError;
use crate::{
Error,
KeyHandle,
packet::Tag,
Packet,
parse::{
Cookie,
Parse,
PacketParserResult,
PacketParser
},
Result,
cert::bundle::ComponentBundle,
Cert,
};
mod low_level;
use low_level::{
Lexer,
CertParser as CertLowLevelParser,
CertParserError,
Token,
parse_error_downcast,
};
const TRACE : bool = false;
#[derive(Debug)]
pub(crate) enum KeyringValidity {
Keyring,
KeyringPrefix,
Error(anyhow::Error),
}
#[allow(unused)]
impl KeyringValidity {
pub fn is_keyring(&self) -> bool {
matches!(self, KeyringValidity::Keyring)
}
pub fn is_keyring_prefix(&self) -> bool {
matches!(self, KeyringValidity::KeyringPrefix)
}
pub fn is_err(&self) -> bool {
matches!(self, KeyringValidity::Error(_))
}
}
#[derive(Debug)]
pub(crate) struct KeyringValidator {
tokens: Vec<Token>,
n_keys: usize,
n_packets: usize,
finished: bool,
error: Option<CertParserError>,
}
impl Default for KeyringValidator {
fn default() -> Self {
KeyringValidator::new()
}
}
#[allow(unused)]
impl KeyringValidator {
pub fn new() -> Self {
KeyringValidator {
tokens: vec![],
n_keys: 0,
n_packets: 0,
finished: false,
error: None,
}
}
pub fn is_keyring(&self) -> bool {
self.check().is_keyring()
}
pub fn is_keyring_prefix(&self) -> bool {
self.check().is_keyring_prefix()
}
pub fn is_err(&self) -> bool {
self.check().is_err()
}
pub fn push_token(&mut self, token: Token) {
assert!(!self.finished);
if self.error.is_some() {
return;
}
if let Token::PublicKey(_) | Token::SecretKey(_) = token {
self.tokens.clear();
self.n_keys += 1;
}
self.n_packets += 1;
match (&token, self.tokens.last()) {
(Token::Signature(None), Some(Token::Signature(None))) => {
},
_ => self.tokens.push(token),
}
}
pub fn push(&mut self, tag: Tag) {
let token = match tag {
Tag::PublicKey => Token::PublicKey(None),
Tag::SecretKey => Token::SecretKey(None),
Tag::PublicSubkey => Token::PublicSubkey(None),
Tag::SecretSubkey => Token::SecretSubkey(None),
Tag::UserID => Token::UserID(None),
Tag::UserAttribute => Token::UserAttribute(None),
Tag::Signature => Token::Signature(None),
Tag::Trust => Token::Trust(None),
Tag::Marker => {
return;
},
Tag::Unknown(_) => Token::Unknown(tag, None),
Tag::Private(_) => Token::Unknown(tag, None),
_ => {
self.error = Some(CertParserError::OpenPGP(
Error::MalformedMessage(
format!("Invalid Cert: {:?} packet (#{}) not expected",
tag, self.n_packets))));
self.tokens.clear();
return;
}
};
self.push_token(token)
}
pub fn finish(&mut self) {
assert!(!self.finished);
self.finished = true;
}
pub fn check(&self) -> KeyringValidity {
if let Some(ref err) = self.error {
return KeyringValidity::Error((*err).clone().into());
}
let r = CertLowLevelParser::new().parse(
Lexer::from_tokens(&self.tokens));
if self.finished {
match r {
Ok(_) => KeyringValidity::Keyring,
Err(err) =>
KeyringValidity::Error(
CertParserError::Parser(parse_error_downcast(err)).into()),
}
} else {
match r {
Ok(_) => KeyringValidity::KeyringPrefix,
Err(ParseError::UnrecognizedEof { .. }) =>
KeyringValidity::KeyringPrefix,
Err(err) =>
KeyringValidity::Error(
CertParserError::Parser(parse_error_downcast(err)).into()),
}
}
}
}
#[derive(Debug)]
#[allow(unused)]
pub(crate) enum CertValidity {
Cert,
CertPrefix,
Error(anyhow::Error),
}
#[allow(unused)]
impl CertValidity {
pub fn is_cert(&self) -> bool {
matches!(self, CertValidity::Cert)
}
pub fn is_cert_prefix(&self) -> bool {
matches!(self, CertValidity::CertPrefix)
}
pub fn is_err(&self) -> bool {
matches!(self, CertValidity::Error(_))
}
}
#[derive(Debug)]
pub(crate) struct CertValidator(KeyringValidator);
impl Default for CertValidator {
fn default() -> Self {
CertValidator::new()
}
}
impl CertValidator {
pub fn new() -> Self {
CertValidator(Default::default())
}
#[cfg(test)]
pub fn push_token(&mut self, token: Token) {
self.0.push_token(token)
}
pub fn push(&mut self, tag: Tag) {
self.0.push(tag)
}
pub fn finish(&mut self) {
self.0.finish()
}
pub fn check(&self) -> CertValidity {
if self.0.n_keys > 1 {
return CertValidity::Error(Error::MalformedMessage(
"More than one key found, this is a keyring".into()).into());
}
match self.0.check() {
KeyringValidity::Keyring => CertValidity::Cert,
KeyringValidity::KeyringPrefix => CertValidity::CertPrefix,
KeyringValidity::Error(e) => CertValidity::Error(e),
}
}
}
#[derive(Default)]
pub struct CertParser<'a> {
source: Option<Box<dyn Iterator<Item=Result<Packet>> + 'a + Send + Sync>>,
packets: Vec<Packet>,
queued_error: Option<anyhow::Error>,
filter: Vec<Box<dyn Send + Sync + Fn(&Cert, bool) -> bool + 'a>>,
}
assert_send_and_sync!(CertParser<'_>);
impl<'a> From<PacketParserResult<'a>> for CertParser<'a>
{
fn from(ppr: PacketParserResult<'a>) -> Self {
use std::io::ErrorKind::UnexpectedEof;
let mut parser : Self = Default::default();
if let PacketParserResult::Some(pp) = ppr {
let mut ppp : Box<Option<PacketParser>> = Box::new(Some(pp));
let mut retry_with_reader = Box::new(None);
parser.source = Some(
Box::new(std::iter::from_fn(move || {
tracer!(TRACE, "PacketParserResult::next", 0);
if let Some(reader) = retry_with_reader.take() {
match PacketParser::from_cookie_reader(reader) {
Ok(PacketParserResult::Some(pp)) => {
*ppp = Some(pp);
},
Ok(PacketParserResult::EOF(_)) =>
(), Err(err) => {
if let Some(e) = err.downcast_ref::<io::Error>()
{
if e.kind() == UnexpectedEof {
return None;
}
}
return Some(Err(err));
},
}
}
if let Some(mut pp) = ppp.take() {
if let Packet::Unknown(_) = pp.packet {
if let Err(e) = pp.buffer_unread_content() {
return Some(Err(e));
}
}
match pp.next() {
Ok((packet, ppr)) => {
match ppr {
PacketParserResult::Some(pp) =>
*ppp = Some(pp),
PacketParserResult::EOF(eof) =>
*retry_with_reader =
Some(eof.into_reader()),
}
t!("PacketParser::next yielded a {}",
packet.tag());
Some(Ok(packet))
},
Err(err) => {
t!("PacketParser::next returned an error: {}.",
err);
Some(Err(err))
}
}
} else {
None
}
})));
}
parser
}
}
impl<'a> From<Vec<Result<Packet>>> for CertParser<'a> {
fn from(p: Vec<Result<Packet>>) -> CertParser<'a> {
CertParser::from_iter(p)
}
}
impl<'a> From<Vec<Packet>> for CertParser<'a> {
fn from(p: Vec<Packet>) -> CertParser<'a> {
CertParser::from_iter(p)
}
}
impl<'a> Parse<'a, CertParser<'a>> for CertParser<'a>
{
fn from_buffered_reader<R>(reader: R) -> Result<CertParser<'a>>
where
R: BufferedReader<Cookie> + 'a,
{
Ok(Self::from(PacketParser::from_buffered_reader(reader.into_boxed())?))
}
}
impl<'a> crate::seal::Sealed for CertParser<'a> {}
impl<'a> CertParser<'a> {
pub fn from_iter<I, J>(iter: I) -> Self
where I: 'a + IntoIterator<Item=J>,
J: 'a + Into<Result<Packet>>,
<I as IntoIterator>::IntoIter: Send + Sync,
{
Self {
source: Some(Box::new(iter.into_iter().map(Into::into))),
..Default::default()
}
}
pub fn unvalidated_cert_filter<F>(mut self, filter: F) -> Self
where F: 'a + Send + Sync + Fn(&Cert, bool) -> bool
{
self.filter.push(Box::new(filter));
self
}
fn parse(&mut self, p: Packet) -> Result<Option<Cert>> {
tracer!(TRACE, "CertParser::parse", 0);
match p {
Packet::Marker(_) => {
return Ok(None);
},
Packet::Padding(_) => {
return Ok(None);
},
p if Cert::valid_packet(&p).is_err()
&& ! p.tag().is_critical() =>
{
return Ok(None);
},
_ => {},
}
if !self.packets.is_empty() {
if self.packets.len() == 1 {
if let Err(err) = Cert::valid_start(&self.packets[0]) {
t!("{}", err);
return self.cert(Some(p));
}
}
if Cert::valid_start(&p).is_ok() {
t!("Encountered the start of a new certificate ({}), \
finishing buffered certificate", p.tag());
return self.cert(Some(p));
} else if let Err(err) = Cert::valid_packet(&p) {
t!("Encountered an invalid packet ({}), \
finishing buffered certificate: {}",
p.tag(), err);
return self.cert(Some(p));
}
}
self.packets.push(p);
Ok(None)
}
fn reset(&mut self) -> Self {
let mut orig = mem::take(self);
self.source = orig.source.take();
mem::swap(&mut self.filter, &mut orig.filter);
orig
}
fn cert(&mut self, pk: Option<Packet>) -> Result<Option<Cert>> {
tracer!(TRACE, "CertParser::cert", 0);
let orig = self.reset();
if let Some(pk) = pk {
self.packets.push(pk);
}
let n_packets = orig.packets.len();
t!("Finalizing certificate with {} packets", n_packets);
let mut failed = false;
let mut packets: Vec<Packet> = Vec::with_capacity(0);
let mut tokens: Vec<Token> = Vec::with_capacity(n_packets);
for p in orig.packets {
if failed {
packets.push(p);
} else {
match p.try_into() {
Ok(t) => tokens.push(t),
Err(p) => {
packets.reserve(n_packets);
for t in tokens.drain(..) {
packets.push({
let p: Option<Packet> = t.into();
p.expect("token created with packet")
});
}
packets.push(p);
failed = true;
},
}
}
}
if failed {
let err = Error::UnsupportedCert(
"Packet sequence includes non-Cert packets.".into(),
packets);
t!("Invalid certificate: {}", err);
return Err(err.into());
}
t!("{} tokens: {:?}", tokens.len(), tokens);
let certo = match CertLowLevelParser::new()
.parse(Lexer::from_tokens(&tokens))
{
Ok(certo) => certo,
Err(err) => {
let err = low_level::parse_error_to_openpgp_error(
low_level::parse_error_downcast(err));
t!("Low level parser: {}", err);
return Err(err.into());
}
}.and_then(|cert| {
for filter in &self.filter {
if !filter(&cert, true) {
t!("Rejected by filter");
return None;
}
}
Some(cert)
}).and_then(|mut cert| {
let primary_fp: KeyHandle = cert.key_handle();
split_sigs(&primary_fp, &mut cert.primary);
for b in cert.userids.iter_mut() {
split_sigs(&primary_fp, b);
}
for b in cert.user_attributes.iter_mut() {
split_sigs(&primary_fp, b);
}
for b in cert.subkeys.iter_mut() {
split_sigs(&primary_fp, b);
}
let cert = cert.canonicalize();
for filter in &self.filter {
if !filter(&cert, true) {
t!("Rejected by filter");
return None;
}
}
Some(cert)
});
t!("Returning {:?}, constructed from {} packets",
certo.as_ref().map(|c| c.fingerprint()),
n_packets);
Ok(certo)
}
}
fn split_sigs<C>(primary: &KeyHandle, b: &mut ComponentBundle<C>)
{
debug_assert!(b.self_signatures.is_empty());
debug_assert!(b.self_revocations.is_empty());
debug_assert!(b.other_revocations.is_empty());
for sig in mem::replace(&mut b.certifications, Vec::with_capacity(0)) {
let typ = sig.typ();
let issuers = sig.get_issuers();
let is_selfsig =
issuers.is_empty()
|| issuers.iter().any(|kh| kh.aliases(primary));
use crate::SignatureType::*;
if typ == CertificationApproval {
b.attestations.push(sig);
} else if typ == KeyRevocation
|| typ == SubkeyRevocation
|| typ == CertificationRevocation
{
if is_selfsig {
b.self_revocations.push(sig);
} else {
b.other_revocations.push(sig);
}
} else if is_selfsig {
b.self_signatures.push(sig);
} else {
b.certifications.push(sig);
}
}
}
impl<'a> Iterator for CertParser<'a> {
type Item = Result<Cert>;
fn next(&mut self) -> Option<Self::Item> {
tracer!(TRACE, "CertParser::next", 0);
if let Some(err) = self.queued_error.take() {
t!("Returning queued error: {}", err);
return Some(Err(err));
}
loop {
match self.source.take() {
None => {
t!("EOF.");
if self.packets.is_empty() {
return None;
}
match self.cert(None) {
Ok(Some(cert)) => return Some(Ok(cert)),
Ok(None) => return None,
Err(err) => return Some(Err(err)),
}
},
Some(mut iter) => {
let r = match iter.next() {
Some(Ok(packet)) => {
t!("Got packet #{} ({}{})",
self.packets.len(), packet.tag(),
match &packet {
Packet::PublicKey(k) =>
Some(k.fingerprint().to_hex()),
Packet::SecretKey(k) =>
Some(k.fingerprint().to_hex()),
Packet::PublicSubkey(k) =>
Some(k.fingerprint().to_hex()),
Packet::SecretSubkey(k) =>
Some(k.fingerprint().to_hex()),
Packet::UserID(u) =>
Some(String::from_utf8_lossy(u.value())
.into()),
Packet::Signature(s) =>
Some(format!("{}", s.typ())),
_ => None,
}
.map(|s| format!(", {}", s))
.unwrap_or_else(|| "".into())
);
self.source = Some(iter);
self.parse(packet)
}
Some(Err(err)) => {
self.source = Some(iter);
t!("Error getting packet: {}", err);
if ! self.packets.is_empty() {
match self.cert(None) {
Ok(Some(cert)) => {
self.queued_error = Some(err);
return Some(Ok(cert));
}
Ok(None) => {
return Some(Err(err));
}
Err(err2) => {
self.queued_error = Some(err2);
return Some(Err(err));
}
}
} else {
return Some(Err(err));
}
}
None if self.packets.is_empty() => {
t!("Packet iterator was empty");
Ok(None)
}
None => {
t!("Packet iterator exhausted after {} packets",
self.packets.len());
self.cert(None)
}
};
match r {
Ok(Some(cert)) => {
t!(" => {}", cert.fingerprint());
return Some(Ok(cert));
}
Ok(None) => (),
Err(err) => return Some(Err(err)),
}
},
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
use std::collections::HashSet;
use std::iter::FromIterator;
use crate::Fingerprint;
use crate::cert::prelude::*;
use crate::packet::prelude::*;
use crate::parse::RECOVERY_THRESHOLD;
use crate::serialize::Serialize;
use crate::types::DataFormat;
use crate::tests;
#[test]
fn push_tokens() {
use crate::cert::parser::low_level::lexer::{Token, Lexer};
use crate::cert::parser::low_level::lexer::Token::*;
use crate::cert::parser::low_level::CertParser;
struct TestVector<'a> {
s: &'a [Token],
result: bool,
}
let test_vectors = [
TestVector {
s: &[ PublicKey(None) ],
result: true,
},
TestVector {
s: &[ SecretKey(None) ],
result: true,
},
TestVector {
s: &[ PublicKey(None), Signature(None) ],
result: true,
},
TestVector {
s: &[ PublicKey(None), Signature(None), Signature(None) ],
result: true,
},
TestVector {
s: &[ PublicKey(None), Signature(None), Signature(None),
UserID(None) ],
result: true,
},
TestVector {
s: &[ PublicKey(None), Signature(None), Signature(None),
UserID(None), Signature(None) ],
result: true,
},
TestVector {
s: &[ PublicKey(None), Signature(None), Signature(None),
UserAttribute(None) ],
result: true,
},
TestVector {
s: &[ PublicKey(None), Signature(None), Signature(None),
UserAttribute(None), Signature(None) ],
result: true,
},
TestVector {
s: &[ PublicKey(None), Signature(None), Signature(None),
PublicSubkey(None) ],
result: true,
},
TestVector {
s: &[ PublicKey(None), Signature(None), Signature(None),
PublicSubkey(None), Signature(None) ],
result: true,
},
TestVector {
s: &[ PublicKey(None), Signature(None), Signature(None),
SecretSubkey(None) ],
result: true,
},
TestVector {
s: &[ PublicKey(None), Signature(None), Signature(None),
SecretSubkey(None), Signature(None) ],
result: true,
},
TestVector {
s: &[ PublicKey(None), Signature(None), Signature(None),
SecretSubkey(None), Signature(None),
SecretSubkey(None), Signature(None),
SecretSubkey(None), Signature(None),
SecretSubkey(None), Signature(None),
SecretSubkey(None), Signature(None),
UserID(None), Signature(None),
Signature(None), Signature(None),
SecretSubkey(None), Signature(None),
UserAttribute(None), Signature(None),
Signature(None), Signature(None),
SecretSubkey(None), Signature(None),
UserID(None),
UserAttribute(None), Signature(None),
Signature(None), Signature(None),
],
result: true,
},
TestVector {
s: &[ PublicKey(None), Signature(None), Signature(None),
PublicKey(None), Signature(None), Signature(None),
],
result: false,
},
TestVector {
s: &[ PublicKey(None), Signature(None), Signature(None),
SecretKey(None), Signature(None), Signature(None),
],
result: false,
},
TestVector {
s: &[ SecretKey(None), Signature(None), Signature(None),
SecretKey(None), Signature(None), Signature(None),
],
result: false,
},
TestVector {
s: &[ SecretKey(None), Signature(None), Signature(None),
PublicKey(None), Signature(None), Signature(None),
],
result: false,
},
TestVector {
s: &[ SecretSubkey(None), Signature(None), Signature(None),
PublicSubkey(None), Signature(None), Signature(None),
],
result: false,
},
TestVector {
s: &[ SecretKey(None), Signature(None),
UserID(None), Signature(None),
SecretSubkey(None), Signature(None),
SecretSubkey(None), Signature(None),
Unknown(Tag::Private(61), None),
],
result: true,
},
];
for v in &test_vectors {
if v.result {
let mut l = CertValidator::new();
for token in v.s.into_iter() {
l.push_token((*token).clone());
assert_match!(CertValidity::CertPrefix = l.check());
}
l.finish();
assert_match!(CertValidity::Cert = l.check());
}
match CertParser::new().parse(Lexer::from_tokens(v.s)) {
Ok(r) => assert!(v.result, "Parsing: {:?} => {:?}", v.s, r),
Err(e) => assert!(! v.result, "Parsing: {:?} => {:?}", v.s, e),
}
}
}
#[test]
fn push_tags() {
use Tag::*;
struct TestVector<'a> {
s: &'a [Tag],
result: bool,
}
let test_vectors = [
TestVector {
s: &[ PublicKey ],
result: true,
},
TestVector {
s: &[ SecretKey, Signature,
UserID, Signature,
SecretSubkey, Signature,
SecretSubkey, Signature,
Tag::Private(61),
],
result: true,
},
TestVector {
s: &[ SecretKey, Signature,
UserID, Signature,
SecretSubkey, Signature,
SecretSubkey, Signature,
Tag::Unknown(61),
],
result: true,
},
TestVector {
s: &[ SecretKey, Signature,
UserID, Signature,
SecretSubkey, Signature,
SecretSubkey, Signature,
Tag::Unknown(61),
SecretKey, Signature,
UserID, Signature,
SecretSubkey, Signature,
SecretSubkey, Signature,
],
result: false,
},
];
for v in &test_vectors {
if v.result {
let mut l = CertValidator::new();
for &tag in v.s.into_iter() {
l.push(tag.clone());
assert_match!(CertValidity::CertPrefix = l.check());
}
l.finish();
assert_match!(CertValidity::Cert = l.check());
}
}
}
#[test]
fn marker_packet_ignored() {
use crate::serialize::Serialize;
let mut testy_with_marker = Vec::new();
Packet::Marker(Default::default())
.serialize(&mut testy_with_marker).unwrap();
testy_with_marker.extend_from_slice(crate::tests::key("testy.pgp"));
CertParser::from(
PacketParser::from_bytes(&testy_with_marker).unwrap())
.next().unwrap().unwrap();
let mut testy_with_marker = Vec::new();
testy_with_marker.extend_from_slice(crate::tests::key("testy.pgp"));
Packet::Marker(Default::default())
.serialize(&mut testy_with_marker).unwrap();
CertParser::from(
PacketParser::from_bytes(&testy_with_marker).unwrap())
.next().unwrap().unwrap();
}
#[test]
fn invalid_packets() -> Result<()> {
tracer!(TRACE, "invalid_packets", 0);
fn cert_cmp(a: &Result<Cert>, b: &Vec<Packet>)
{
let a =
a.as_ref().unwrap().clone().into_packets().collect::<Vec<_>>();
for (i, (a, b)) in a.iter().zip(b).enumerate() {
if a != b {
panic!("Differ at element #{}:\n {:?}\n {:?}",
i, a, b);
}
}
if a.len() != b.len() {
panic!("Different lengths (common prefix identical): {} vs. {}",
a.len(), b.len());
}
}
let (cert, _) =
CertBuilder::general_purpose(Some("alice@example.org"))
.generate()?;
let cert = cert.into_packets().collect::<Vec<_>>();
let userid : Packet = cert.clone()
.into_iter()
.filter(|p| p.tag() == Tag::UserID)
.next()
.unwrap();
let tag = Tag::Private(61);
let unknown : Packet
= Unknown::new(tag, Error::UnsupportedPacketType(tag).into())
.into();
let mut lit = Literal::new(DataFormat::Unicode);
lit.set_body(b"test".to_vec());
let lit = Packet::from(lit);
let cd = {
use crate::types::CompressionAlgorithm;
use crate::packet;
use crate::PacketPile;
use crate::serialize::Serialize;
use crate::parse::Parse;
let mut cd = CompressedData::new(
CompressionAlgorithm::Uncompressed);
let mut body = Vec::new();
lit.serialize(&mut body)?;
cd.set_body(packet::Body::Processed(body));
let cd = Packet::from(cd);
let mut bytes = Vec::new();
cd.serialize(&mut bytes)?;
let pp = PacketPile::from_bytes(&bytes[..])?;
assert_eq!(pp.descendants().count(), 2);
assert_eq!(pp.path_ref(&[ 0 ]).unwrap().tag(),
packet::Tag::CompressedData);
assert_eq!(pp.path_ref(&[ 0, 0 ]), Some(&lit));
cd
};
t!("A single cert.");
let cp = CertParser::from_iter(cert.clone()).collect::<Vec<_>>();
assert_eq!(cp.len(), 1);
cert_cmp(&cp[0], &cert);
t!("Two certificates.");
let cp = CertParser::from_iter(
cert.clone().into_iter().chain(cert.clone())).collect::<Vec<_>>();
assert_eq!(cp.len(), 2);
cert_cmp(&cp[0], &cert);
cert_cmp(&cp[1], &cert);
fn interleave(cert: &Vec<Packet>, p: &Packet) {
t!("A certificate, a {}.", p.tag());
let cp = CertParser::from_iter(
cert.clone().into_iter()
.chain(p.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 2);
cert_cmp(&cp[0], cert);
assert!(cp[1].is_err());
t!("A certificate, two {}.", p.tag());
let cp = CertParser::from_iter(
cert.clone().into_iter()
.chain(p.clone())
.chain(p.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 3);
cert_cmp(&cp[0], cert);
assert!(cp[1].is_err());
assert!(cp[2].is_err());
t!("A {}, a certificate.", p.tag());
let cp = CertParser::from_iter(
p.clone().into_iter()
.chain(cert.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 2);
assert!(cp[0].is_err());
cert_cmp(&cp[1], cert);
t!("Two {}, a certificate.", p.tag());
let cp = CertParser::from_iter(
p.clone().into_iter()
.chain(p.clone())
.chain(cert.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 3);
assert!(cp[0].is_err());
assert!(cp[1].is_err());
cert_cmp(&cp[2], cert);
t!("Two {}, a certificate, two {}.", p.tag(), p.tag());
let cp = CertParser::from_iter(
p.clone().into_iter()
.chain(p.clone())
.chain(cert.clone())
.chain(p.clone())
.chain(p.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 5);
assert!(cp[0].is_err());
assert!(cp[1].is_err());
cert_cmp(&cp[2], cert);
assert!(cp[3].is_err());
assert!(cp[4].is_err());
t!("Two {}, two certificates, two {}, a certificate.");
let cp = CertParser::from_iter(
p.clone().into_iter()
.chain(p.clone())
.chain(cert.clone())
.chain(cert.clone())
.chain(p.clone())
.chain(p.clone())
.chain(cert.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 7);
assert!(cp[0].is_err());
assert!(cp[1].is_err());
cert_cmp(&cp[2], cert);
cert_cmp(&cp[3], cert);
assert!(cp[4].is_err());
assert!(cp[5].is_err());
cert_cmp(&cp[6], cert);
}
interleave(&cert, &lit);
interleave(&cert, &cd);
let mut cert_plus = cert.clone();
cert_plus.push(unknown.clone());
t!("A certificate, an unknown.");
let cp = CertParser::from_iter(
cert.clone().into_iter()
.chain(unknown.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 1);
cert_cmp(&cp[0], &cert_plus);
t!("An unknown, a certificate.");
let cp = CertParser::from_iter(
unknown.clone().into_iter()
.chain(cert.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 2);
assert!(cp[0].is_err());
cert_cmp(&cp[1], &cert);
t!("A certificate, two unknowns.");
let cp = CertParser::from_iter(
cert.clone().into_iter()
.chain(unknown.clone())
.chain(unknown.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 1);
cert_cmp(&cp[0], &cert_plus);
t!("A certificate, an unknown, a certificate.");
let cp = CertParser::from_iter(
cert.clone().into_iter()
.chain(unknown.clone())
.chain(cert.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 2);
cert_cmp(&cp[0], &cert_plus);
cert_cmp(&cp[1], &cert);
t!("A Literal, two User IDs");
let cp = CertParser::from_iter(
lit.clone().into_iter()
.chain(userid.clone())
.chain(userid.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 3);
assert!(cp[0].is_err());
assert!(cp[1].is_err());
assert!(cp[2].is_err());
t!("A User ID, a certificate");
let cp = CertParser::from_iter(
userid.clone().into_iter()
.chain(cert.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 2);
assert!(cp[0].is_err());
cert_cmp(&cp[1], &cert);
t!("Two User IDs, a certificate");
let cp = CertParser::from_iter(
userid.clone().into_iter()
.chain(userid.clone())
.chain(cert.clone()))
.collect::<Vec<_>>();
assert_eq!(cp.len(), 3);
assert!(cp[0].is_err());
assert!(cp[1].is_err());
cert_cmp(&cp[2], &cert);
Ok(())
}
#[test]
fn concatenated_armored_certs() -> Result<()> {
let mut keyring = Vec::new();
keyring.extend_from_slice(b"some\ntext\n");
keyring.extend_from_slice(crate::tests::key("testy.asc"));
keyring.extend_from_slice(crate::tests::key("testy.asc"));
keyring.extend_from_slice(b"some\ntext\n");
keyring.extend_from_slice(crate::tests::key("testy.asc"));
keyring.extend_from_slice(b"some\ntext\n");
let certs = CertParser::from_bytes(&keyring)?.collect::<Vec<_>>();
assert_eq!(certs.len(), 3);
assert!(certs.iter().all(|c| c.is_ok()));
Ok(())
}
fn parse_test(n: usize, literal: bool, bad: usize) -> Result<()> {
tracer!(TRACE, "t", 0);
let nulls = vec![ 0; bad ];
t!("n: {}, literals: {}, bad data: {}",
n, literal, bad);
let mut data = Vec::new();
let mut certs_orig = vec![];
for i in 0..n {
let (cert, _) =
CertBuilder::general_purpose(
Some(format!("{}@example.org", i)))
.generate()?;
cert.as_tsk().serialize(&mut data)?;
certs_orig.push(cert);
if literal {
let mut lit = Literal::new(DataFormat::Unicode);
lit.set_body(b"data".to_vec());
Packet::from(lit).serialize(&mut data)?;
}
data.extend(&nulls[..bad]);
}
if n == 0 {
data.extend(&nulls[..bad]);
}
assert_eq!(certs_orig.len(), n);
t!("Start of data: {} {}",
if let Some(x) = data.get(0) {
format!("{:02X}", x)
} else {
"XX".into()
},
if let Some(x) = data.get(1) {
format!("{:02X}", x)
} else {
"XX".into()
});
let certs_parsed = CertParser::from_bytes(&data);
let certs_parsed = if n == 0 && bad > 0 {
assert!(certs_parsed.is_err());
return Ok(());
} else {
certs_parsed.expect("Valid init")
};
let certs_parsed: Vec<_> = certs_parsed.collect();
certs_parsed.iter().enumerate().for_each(|(i, r)| {
t!("{}. {}",
i,
match r {
Ok(c) => c.fingerprint().to_string(),
Err(err) => err.to_string(),
});
});
let n = if bad > RECOVERY_THRESHOLD {
certs_orig.drain(1..);
std::cmp::min(n, 1)
} else {
n
};
let modulus = if literal && bad > 0 {
3
} else {
2
};
let certs_parsed: Vec<Cert> = certs_parsed.into_iter()
.enumerate()
.filter_map(|(i, c)| {
if literal && i % modulus == 1 {
assert!(c.is_err());
None
} else if bad > 0 && n == 0 && i == 0 {
assert!(c.is_err());
None
} else if bad > 0 && i % modulus == modulus - 1 {
assert!(c.is_err());
None
} else {
Some(c.unwrap())
}
})
.collect();
assert_eq!(certs_orig.len(), certs_parsed.len(),
"number of parsed certificates: expected vs. got");
let fpr_orig = certs_orig.iter()
.map(|c| {
c.fingerprint()
})
.collect::<Vec<_>>();
let fpr_parsed = certs_parsed.iter()
.map(|c| {
c.fingerprint()
})
.collect::<Vec<_>>();
if fpr_orig != fpr_parsed {
t!("{} certificates in orig; {} is parsed",
fpr_orig.len(), fpr_parsed.len());
let fpr_set_orig: HashSet<&Fingerprint>
= HashSet::from_iter(fpr_orig.iter());
let fpr_set_parsed = HashSet::from_iter(fpr_parsed.iter());
t!("Only in orig:\n {}",
fpr_set_orig.difference(&fpr_set_parsed)
.map(|f| f.to_string())
.collect::<Vec<_>>()
.join(",\n "));
t!("Only in parsed:\n {}",
fpr_set_parsed.difference(&fpr_set_orig)
.map(|f| f.to_string())
.collect::<Vec<_>>()
.join(",\n "));
assert_eq!(fpr_orig, fpr_parsed);
}
for (i, (c_orig, c_parsed)) in
certs_orig
.into_iter()
.zip(certs_parsed.into_iter())
.enumerate()
{
let ps_orig: Vec<Packet> =
c_orig.as_tsk().into_packets().collect();
let ps_parsed: Vec<Packet> =
c_parsed.as_tsk().into_packets().collect();
assert_eq!(ps_orig.len(), ps_parsed.len(),
"number of packets: expected vs. got");
for (j, (p_orig, p_parsed)) in
ps_orig
.into_iter()
.zip(ps_parsed.into_iter())
.enumerate()
{
assert_eq!(p_orig, p_parsed,
"Cert {}, packet: {}", i, j);
}
}
Ok(())
}
#[test]
fn parse_keyring_simple() -> Result<()> {
for n in [1, 100, 0].iter() {
parse_test(*n, false, 0)?;
}
Ok(())
}
#[test]
fn parse_keyring_interleaved_literals() -> Result<()> {
for n in [1, 100, 0].iter() {
parse_test(*n, true, 0)?;
}
Ok(())
}
#[test]
fn parse_keyring_interleaved_small_junk() -> Result<()> {
for n in [1, 100, 0].iter() {
parse_test(*n, false, 1)?;
}
Ok(())
}
#[test]
fn parse_keyring_interleaved_unrecoverable_junk() -> Result<()> {
for n in [1, 100, 0].iter() {
parse_test(*n, false, 2 * RECOVERY_THRESHOLD)?;
}
Ok(())
}
#[test]
fn parse_keyring_interleaved_literal_and_small_junk() -> Result<()> {
for n in [1, 100, 0].iter() {
parse_test(*n, true, 1)?;
}
Ok(())
}
#[test]
fn parse_keyring_interleaved_literal_and_unrecoverable_junk() -> Result<()> {
for n in [1, 100, 0].iter() {
parse_test(*n, true, 2 * RECOVERY_THRESHOLD)?;
}
Ok(())
}
#[test]
fn parse_keyring_no_public_key() -> Result<()> {
tracer!(TRACE, "parse_keyring_no_public_key", 0);
let (cert_1, _) =
CertBuilder::general_purpose(
Some("ea@example.org"))
.generate()?;
let cert_1_packets: Vec<Packet>
= cert_1.into_packets().collect();
let (cert_2, _) =
CertBuilder::general_purpose(
Some("eb@example.org"))
.generate()?;
for n in 1..cert_1_packets.len() {
t!("n: {}", n);
let mut data = Vec::new();
for i in n..cert_1_packets.len() {
cert_1_packets[i].serialize(&mut data)?;
}
cert_2.as_tsk().serialize(&mut data)?;
let certs_parsed = CertParser::from_bytes(&data)
.expect("Valid parse");
let mut iter = certs_parsed;
for _ in n..cert_1_packets.len() {
assert!(iter.next().unwrap().is_err());
}
assert_eq!(iter.next().unwrap().as_ref().unwrap(), &cert_2);
assert!(iter.next().is_none());
assert!(iter.next().is_none());
}
Ok(())
}
#[test]
fn filter() {
let fp = Fingerprint::from_hex(
"CBCD8F030588653EEDD7E2659B7DD433F254904A",
).unwrap();
let cp = CertParser::from_bytes(tests::key("bad-subkey-keyring.pgp"))
.unwrap()
.unvalidated_cert_filter(|cert, _| {
cert.fingerprint() == fp
});
let certs = cp.collect::<Result<Vec<Cert>>>().unwrap();
assert_eq!(certs.len(), 1);
assert!(certs[0].fingerprint() == fp);
}
#[test]
fn packet_source_includes_an_error() -> Result<()> {
let mut ppr
= PacketParser::from_bytes(crate::tests::key("testy.pgp"))?;
let mut testy = Vec::new();
while let PacketParserResult::Some(pp) = ppr {
let (packet, ppr_) = pp.next()?;
testy.push(packet);
ppr = ppr_;
}
let mut packets: Vec<Result<Packet>> = Vec::new();
for p in testy.iter() {
packets.push(Ok(p.clone()));
}
packets.push(Err(anyhow::anyhow!("An error")));
packets.push(Err(anyhow::anyhow!("Another error")));
for p in testy.iter() {
packets.push(Ok(p.clone()));
}
let certs = CertParser::from(packets).collect::<Vec<Result<Cert>>>();
assert_eq!(certs.len(), 4);
assert!(certs[0].is_ok());
assert!(certs[1].is_err());
assert!(certs[2].is_err());
assert!(certs[3].is_ok());
Ok(())
}
}