use std::borrow::Cow;
use std::convert::TryFrom;
use std::fmt;
use std::io::Read;
use std::path::Path;
use buffered_reader;
use buffered_reader::BufferedReader;
use crate::Error;
use crate::Fingerprint;
use crate::KeyID;
use crate::Result;
use crate::armor;
use crate::cert::Cert;
use crate::packet::Header;
use crate::packet::Key;
use crate::packet::Packet;
use crate::packet::Tag;
use crate::packet::UserID;
use crate::packet::header::BodyLength;
use crate::packet::header::CTB;
use crate::packet::key;
use crate::parse::PacketParser;
use crate::parse::Parse;
use crate::parse::RECOVERY_THRESHOLD;
use super::TRACE;
mod iter;
pub use iter::KeyIter;
#[derive(Clone, PartialEq, Eq)]
pub struct RawPacket<'a> {
tag: Tag,
header_len: usize,
data: &'a [u8],
}
assert_send_and_sync!(RawPacket<'_>);
impl fmt::Debug for RawPacket<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RawPacket")
.field("tag", &self.tag)
.field("data (bytes)", &self.data.len())
.finish()
}
}
impl<'a> RawPacket<'a> {
fn new(tag: Tag, header_len: usize, bytes: &'a [u8]) -> Self {
Self {
tag,
header_len,
data: bytes,
}
}
pub fn tag(&self) -> Tag {
self.tag
}
pub fn as_bytes(&self) -> &[u8] {
self.data
}
pub fn body(&self) -> &[u8] {
&self.data[self.header_len..]
}
}
impl<'a> TryFrom<RawPacket<'a>> for Packet {
type Error = anyhow::Error;
fn try_from(p: RawPacket<'a>) -> Result<Self> {
Packet::from_bytes(p.as_bytes())
}
}
impl<'a> crate::seal::Sealed for RawPacket<'a> {}
impl<'a> crate::serialize::Marshal for RawPacket<'a> {
fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> {
o.write_all(self.as_bytes())?;
Ok(())
}
}
#[derive(Clone)]
pub struct RawCert<'a> {
data: Cow<'a, [u8]>,
fingerprint: Fingerprint,
packets: Vec<(Tag, usize, usize)>,
}
assert_send_and_sync!(RawCert<'_>);
impl<'a> fmt::Debug for RawCert<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RawCert")
.field("fingerprint", &self.fingerprint)
.field("packets",
&self.packets
.iter()
.map(|p| format!("{} (offset: {})", p.0, p.1))
.collect::<Vec<String>>()
.join(", "))
.field("data (bytes)", &self.data.as_ref().len())
.finish()
}
}
impl<'a> PartialEq for RawCert<'a> {
fn eq(&self, other: &Self) -> bool {
self.data == other.data
}
}
impl<'a> Eq for RawCert<'a> {
}
impl<'a> RawCert<'a> {
pub fn as_bytes(&'a self) -> &'a [u8] {
self.data.as_ref()
}
pub fn fingerprint(&self) -> Fingerprint {
self.fingerprint.clone()
}
pub fn keyid(&self) -> KeyID {
KeyID::from(&self.fingerprint)
}
pub fn packet(&self, i: usize) -> Option<RawPacket> {
let data: &[u8] = self.data.as_ref();
let &(tag, header_len, start) = self.packets.get(i)?;
let following = self.packets
.get(i + 1)
.map(|&(_, _, offset)| offset)
.unwrap_or(data.len());
Some(RawPacket::new(tag, header_len, &data[start..following]))
}
pub fn packets(&self) -> impl Iterator<Item=RawPacket> {
let data: &[u8] = self.data.as_ref();
let count = self.packets.len();
(0..count)
.map(move |i| {
let (tag, header_len, start) = self.packets[i];
let following = self.packets
.get(i + 1)
.map(|&(_, _, offset)| offset)
.unwrap_or(data.len());
RawPacket::new(tag, header_len, &data[start..following])
})
}
pub fn count(&self) -> usize {
self.packets.len()
}
pub fn keys(&self) -> KeyIter<key::PublicParts, key::UnspecifiedRole> {
KeyIter::new(self)
}
fn keys_internal(&self)
-> impl Iterator<Item=Key<key::PublicParts, key::UnspecifiedRole>> + '_
{
self.packets()
.filter_map(|p| {
if matches!(p.tag(),
Tag::PublicKey | Tag::PublicSubkey
| Tag::SecretKey | Tag::SecretSubkey)
{
Key::from_bytes(p.body())
.ok()
.map(|k| k.parts_into_public())
} else {
None
}
})
}
pub fn primary_key(&self) -> Key<key::PublicParts, key::PrimaryRole> {
self.keys().next().expect("have a primary key").role_into_primary()
}
pub fn userids(&self) -> impl Iterator<Item=UserID> + '_
{
self.packets()
.filter_map(|p| {
if p.tag() == Tag::UserID {
UserID::try_from(p.body()).ok()
} else {
None
}
})
}
}
impl<'a> TryFrom<&RawCert<'a>> for Cert {
type Error = anyhow::Error;
fn try_from(c: &RawCert) -> Result<Self> {
Cert::from_bytes(c.as_bytes())
}
}
impl<'a> TryFrom<RawCert<'a>> for Cert {
type Error = anyhow::Error;
fn try_from(c: RawCert) -> Result<Self> {
Cert::try_from(&c)
}
}
impl<'a> crate::seal::Sealed for RawCert<'a> {}
impl<'a> crate::serialize::Marshal for RawCert<'a> {
fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> {
o.write_all(self.as_bytes())?;
Ok(())
}
}
pub struct RawCertParser<'a>
{
slice: Option<&'a [u8]>,
reader: Box<dyn BufferedReader<()> + 'a>,
dearmor: bool,
bytes_read: usize,
pending_error: Option<anyhow::Error>,
done: bool,
}
assert_send_and_sync!(RawCertParser<'_>);
impl<'a> RawCertParser<'a> {
fn new<R>(reader: R) -> Result<Self>
where R: 'a + BufferedReader<()>
{
let mut dearmor = false;
let mut dup = buffered_reader::Dup::new(reader);
if ! dup.eof() {
match Header::parse(&mut dup) {
Ok(header) => {
let tag = header.ctb().tag();
if matches!(tag, Tag::Unknown(_) | Tag::Private(_)) {
return Err(Error::MalformedCert(
format!("A certificate must start with a \
public key or a secret key packet, \
got a {}",
tag))
.into());
}
}
Err(_err) => {
dearmor = true;
}
}
}
let mut reader = dup.as_boxed().into_inner().expect("inner");
if dearmor {
reader
= buffered_reader::Adapter::new(
armor::Reader::from_buffered_reader(
buffered_reader::Adapter::with_cookie(
reader, Default::default()).as_boxed(),
armor::ReaderMode::Tolerant(None),
Default::default())
.as_boxed())
.as_boxed();
let mut dup = buffered_reader::Dup::new(reader);
match Header::parse(&mut dup) {
Ok(header) => {
let tag = header.ctb().tag();
if matches!(tag, Tag::Unknown(_) | Tag::Private(_)) {
return Err(Error::MalformedCert(
format!("A certificate must start with a \
public key or a secret key packet, \
got a {}",
tag))
.into());
}
}
Err(err) => {
return Err(err);
}
}
reader = dup.as_boxed().into_inner().expect("inner");
}
Ok(RawCertParser {
slice: None,
reader,
dearmor,
bytes_read: 0,
pending_error: None,
done: false,
})
}
}
impl<'a> Parse<'a, RawCertParser<'a>> for RawCertParser<'a>
{
fn from_reader<R: 'a + Read + Send + Sync>(reader: R) -> Result<Self> {
RawCertParser::new(buffered_reader::Generic::new(reader, None))
}
fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
RawCertParser::new(buffered_reader::File::open(path)?)
}
fn from_bytes<D: AsRef<[u8]> + ?Sized + Send + Sync>(data: &'a D) -> Result<Self> {
let data = data.as_ref();
let mut p = RawCertParser::new(buffered_reader::Memory::new(data))?;
if ! p.dearmor {
p.slice = Some(data);
}
Ok(p)
}
}
impl<'a> Iterator for RawCertParser<'a>
{
type Item = Result<RawCert<'a>>;
fn next(&mut self) -> Option<Self::Item> {
tracer!(TRACE, "RawCertParser::next", 0);
if let Some(err) = self.pending_error.take() {
t!("Returning the queued error: {}", err);
return Some(Err(err));
}
if self.done {
return None;
}
if self.reader.eof() {
return None;
}
let mut reader = buffered_reader::Dup::new(
std::mem::replace(&mut self.reader,
Box::new(buffered_reader::EOF::new())));
let cert_start_absolute = self.bytes_read;
let mut processed = 0;
let mut cert_start = 0;
let mut cert_end = 0;
let mut packets: Vec<(Tag, usize, usize)> = Vec::new();
let mut fingerprint = None;
let mut pending_error = None;
'packet_parser: loop {
if reader.eof() {
break;
}
let packet_start = reader.total_out();
processed = packet_start;
let mut skip = 0;
let mut header_len = 0;
let header = loop {
match Header::parse(&mut reader) {
Err(err) => {
if skip == 0 {
t!("Reading the next packet's header: {}", err);
}
if skip >= RECOVERY_THRESHOLD {
pending_error = Some(err.context(
format!("Splitting keyring at offset {}",
self.bytes_read + packet_start)));
processed = reader.total_out();
self.done = true;
break 'packet_parser;
} else if reader.eof() {
t!("EOF while trying to recover");
skip += 1;
break Header::new(CTB::new(Tag::Reserved),
BodyLength::Full(skip as u32));
} else {
skip += 1;
reader.rewind();
reader.consume(packet_start + skip);
}
}
Ok(header) if skip > 0 => {
if PacketParser::plausible_cert(&mut reader, &header)
.is_ok()
{
t!("Found a valid header after {} bytes \
of junk: {:?}",
skip, header);
break Header::new(CTB::new(Tag::Reserved),
BodyLength::Full(skip as u32));
} else {
skip += 1;
reader.rewind();
reader.consume(packet_start + skip);
}
}
Ok(header) => {
header_len = reader.total_out() - packet_start;
break header;
}
}
};
if skip > 0 {
t!("Recovered after {} bytes of junk", skip);
pending_error = Some(Error::MalformedPacket(
format!("Encountered {} bytes of junk at offset {}",
skip, self.bytes_read)).into());
processed += skip;
break;
}
let tag = header.ctb().tag();
t!("Found a {:?}, length: {:?}",
tag, header.length());
if packet_start > cert_start
&& (tag == Tag::PublicKey || tag == Tag::SecretKey)
{
t!("Stopping: found the start of a new cert ({})", tag);
break;
}
match header.length() {
BodyLength::Full(l) => {
let l = *l as usize;
match reader.data_consume_hard(l) {
Err(err) => {
t!("Stopping: reading {}'s body: {}", tag, err);
pending_error = Some(err.into());
break;
}
Ok(data) => {
if tag == Tag::PublicKey
|| tag == Tag::SecretKey
{
let data = &data[..l];
match Key::from_bytes(data) {
Err(err) => {
t!("Stopping: parsing public key: {}",
err);
pending_error = Some(err);
break;
}
Ok(key) => {
fingerprint = Some(key.fingerprint());
}
}
}
}
}
}
BodyLength::Partial(_) => {
t!("Stopping: Partial body length not allowed \
for {} packets",
tag);
pending_error = Some(
Error::MalformedPacket(
format!("Packet {} uses partial body length \
encoding, which is not allowed in \
certificates",
tag))
.into());
self.done = true;
break;
}
BodyLength::Indeterminate => {
t!("Stopping: Indeterminate length not allowed \
for {} packets",
tag);
pending_error = Some(
Error::MalformedPacket(
format!("Packet {} uses intedeterminite length \
encoding, which is not allowed in \
certificates",
tag))
.into());
self.done = true;
break;
}
}
let end = reader.total_out();
processed = end;
let r = if packet_start == cert_start {
if tag == Tag::Marker {
cert_start = end;
Ok(())
} else {
packets.push((tag, header_len, packet_start));
Cert::valid_start(tag)
}
} else {
packets.push((tag, header_len, packet_start));
Cert::valid_packet(tag)
};
if let Err(err) = r {
t!("Stopping: {:?} => not a certificate: {}", header, err);
pending_error = Some(err);
if self.bytes_read == 0 && packet_start == cert_start
&& matches!(tag, Tag::Unknown(_) | Tag::Private(_))
{
self.done = true;
}
break;
}
cert_end = end;
}
t!("{} bytes processed; RawCert @ offset {}, {} bytes",
processed,
self.bytes_read + cert_start, cert_end - cert_start);
assert!(cert_start <= cert_end);
assert!(cert_end <= processed);
self.bytes_read += processed;
self.reader = Box::new(reader).into_inner()
.expect("just put it there");
let cert_data = &self.reader
.data_consume_hard(processed)
.expect("just read it")[cert_start..cert_end];
if let Some(err) = pending_error.take() {
if cert_start == cert_end {
t!("Directly returning the error");
return Some(Err(err));
} else {
t!("Queuing the error");
self.pending_error = Some(err);
}
}
if cert_start == cert_end {
t!("No data.");
return None;
}
Some(Ok(RawCert {
data: if let Some(slice) = self.slice.as_ref() {
let data = &slice[cert_start_absolute + cert_start
..cert_start_absolute + cert_end];
assert_eq!(data, cert_data);
Cow::Borrowed(data)
} else {
Cow::Owned(cert_data.to_vec())
},
fingerprint: fingerprint.expect("set"),
packets,
}))
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::cert::CertParser;
use crate::cert::CertBuilder;
use crate::packet::Literal;
use crate::parse::RECOVERY_THRESHOLD;
use crate::parse::PacketParserResult;
use crate::serialize::Serialize;
use crate::types::DataFormat;
use crate::packet::Unknown;
use crate::packet::CompressedData;
fn cert_cmp(a: Cert, b: Cert)
{
if a == b {
return;
}
let a: Vec<Packet> = a.into();
let b: Vec<Packet> = b.into();
for (i, (a, b)) in a.iter().zip(b.iter()).enumerate() {
if a != b {
panic!("Differ at element #{}:\n {:?}\n {:?}",
i, a, b);
}
}
if a.len() > b.len() {
eprintln!("Left has more packets:");
for p in &a[b.len()..] {
eprintln!(" - {}", p.tag());
}
}
if b.len() > a.len() {
eprintln!("Right has more packets:");
for p in &b[a.len()..] {
eprintln!(" - {}", p.tag());
}
}
if a.len() != b.len() {
panic!("Different lengths (common prefix identical): {} vs. {}",
a.len(), b.len());
}
}
fn compare_parse(bytes: &[u8]) -> Vec<RawCert> {
let mut result = Vec::new();
for &from_bytes in [true, false].iter() {
let cp = CertParser::from_bytes(bytes);
let rp = if from_bytes {
eprintln!("=== RawCertParser::from_bytes");
RawCertParser::from_bytes(bytes)
} else {
eprintln!("=== RawCertParser::from_reader");
RawCertParser::from_reader(std::io::Cursor::new(bytes))
};
assert_eq!(cp.is_err(), rp.is_err(),
"CertParser: {:?}; RawCertParser: {:?}",
cp.map(|_| "Parsed"),
rp.map(|_| "Parsed"));
if cp.is_err() && rp.is_err() {
return Vec::new();
}
let mut cp = cp.expect("valid");
let mut rp = rp.expect("valid");
let mut raw_certs = Vec::new();
loop {
eprintln!("=== NEXT CERTPARSER");
let c = cp.next();
eprintln!("=== END CERTPARSER");
eprintln!("=== NEXT RAWCERTPARSER");
let r = rp.next();
eprintln!("=== END RAWCERTPARSER");
let (c, r) = match (c, r) {
(Some(Ok(c)), Some(Ok(r))) => (c, r),
(Some(Err(_)), Some(Err(_))) => continue,
(None, None) => break,
(c, r) => {
panic!("\n\
CertParser returned: {:?}\n\
RawCertParser returned: {:?}",
c, r);
}
};
assert_eq!(c.fingerprint(), r.fingerprint());
eprintln!("CertParser says:");
for (i, p) in c.clone().into_iter().enumerate() {
eprintln!(" - {}. {}", i, p.tag());
}
let rp = Cert::from_bytes(r.as_bytes()).unwrap();
eprintln!("RawCertParser says:");
for (i, p) in rp.clone().into_iter().enumerate() {
eprintln!(" - {}. {}", i, p.tag());
}
cert_cmp(c.clone(), rp);
raw_certs.push(r);
}
result = raw_certs;
}
result
}
#[test]
fn empty() {
let bytes = &[];
let certs = compare_parse(bytes);
assert_eq!(certs.len(), 0);
}
#[test]
fn a_cert() {
let testy = crate::tests::key("testy.pgp");
let bytes = testy;
let certs = compare_parse(bytes);
assert_eq!(certs.len(), 1);
let cert = &certs[0];
assert_eq!(cert.as_bytes(), testy);
let tags = &[ Tag::PublicKey,
Tag::UserID, Tag::Signature,
Tag::PublicSubkey, Tag::Signature
];
assert_eq!(
&cert.packets().map(|p| p.tag()).collect::<Vec<Tag>>()[..],
tags);
for (p, tag) in cert.packets().zip(tags.iter()) {
let ppr = PacketParser::from_bytes(p.as_bytes()).expect("valid");
if let PacketParserResult::Some(pp) = ppr {
let (p, pp) = pp.next().expect("valid");
assert_eq!(p.tag(), *tag);
assert!(matches!(pp, PacketParserResult::EOF(_)));
} else {
panic!("Unexpected EOF");
}
}
}
#[test]
fn two_certs() {
let testy = crate::tests::key("testy.pgp");
let mut bytes = testy.to_vec();
bytes.extend_from_slice(testy);
let certs = compare_parse(&bytes[..]);
assert_eq!(certs.len(), 2);
for cert in certs.into_iter() {
assert_eq!(cert.as_bytes(), testy);
assert_eq!(
&cert.packets().map(|p| p.tag()).collect::<Vec<Tag>>()[..],
&[ Tag::PublicKey,
Tag::UserID, Tag::Signature,
Tag::PublicSubkey, Tag::Signature
]);
}
}
#[test]
fn marker_packet_ignored() {
use crate::serialize::Serialize;
let mut marker = Vec::new();
Packet::Marker(Default::default())
.serialize(&mut marker).unwrap();
compare_parse(&marker[..]);
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"));
compare_parse(&testy_with_marker[..]);
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();
compare_parse(&testy_with_marker[..]);
}
#[test]
fn invalid_packets() -> Result<()> {
tracer!(TRACE, "invalid_packets", 0);
let (cert, _) =
CertBuilder::general_purpose(None, Some("alice@example.org"))
.generate()?;
let cert : Vec<Packet> = cert.into();
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::Text);
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
};
fn check(input: impl Iterator<Item=Packet>) {
let mut bytes = Vec::new();
for p in input {
p.serialize(&mut bytes).unwrap();
}
compare_parse(&bytes[..]);
}
fn interleave(cert: &Vec<Packet>, p: &Packet) {
t!("A certificate, a {}.", p.tag());
check(
cert.clone().into_iter()
.chain(p.clone()));
t!("A certificate, two {}.", p.tag());
check(
cert.clone().into_iter()
.chain(p.clone())
.chain(p.clone()));
t!("A {}, a certificate.", p.tag());
check(
p.clone().into_iter()
.chain(cert.clone()));
t!("Two {}, a certificate.", p.tag());
check(
p.clone().into_iter()
.chain(p.clone())
.chain(cert.clone()));
t!("Two {}, a certificate, two {}.", p.tag(), p.tag());
check(
p.clone().into_iter()
.chain(p.clone())
.chain(cert.clone())
.chain(p.clone())
.chain(p.clone()));
t!("Two {}, two certificates, two {}, a certificate.");
check(
p.clone().into_iter()
.chain(p.clone())
.chain(cert.clone())
.chain(cert.clone())
.chain(p.clone())
.chain(p.clone())
.chain(cert.clone()));
}
interleave(&cert, &lit);
interleave(&cert, &cd);
let mut cert_plus = cert.clone();
cert_plus.push(unknown.clone());
t!("A certificate, an unknown.");
check(
cert.clone().into_iter()
.chain(unknown.clone()));
t!("An unknown, a certificate.");
check(
unknown.clone().into_iter()
.chain(cert.clone()));
t!("A certificate, two unknowns.");
check(
cert.clone().into_iter()
.chain(unknown.clone())
.chain(unknown.clone()));
t!("A certificate, an unknown, a certificate.");
check(
cert.clone().into_iter()
.chain(unknown.clone())
.chain(cert.clone()));
t!("A Literal, two User IDs");
check(
lit.clone().into_iter()
.chain(userid.clone())
.chain(userid.clone()));
t!("A User ID, a certificate");
check(
userid.clone().into_iter()
.chain(cert.clone()));
t!("Two User IDs, a certificate");
check(
userid.clone().into_iter()
.chain(userid.clone())
.chain(cert.clone()));
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(
None, Some(format!("{}@example.org", i)))
.generate()?;
cert.as_tsk().serialize(&mut data)?;
certs_orig.push(cert);
if literal {
let mut lit = Literal::new(DataFormat::Text);
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()
});
compare_parse(&data);
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(
None, Some("a@example.org"))
.generate()?;
let cert_1_packets: Vec<Packet>
= cert_1.into_packets().collect();
let (cert_2, _) =
CertBuilder::general_purpose(
None, Some("b@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)?;
compare_parse(&data);
}
Ok(())
}
#[test]
fn accessors() {
let testy = crate::tests::key("testy.pgp");
let certs = RawCertParser::from_bytes(testy)
.expect("valid")
.collect::<Result<Vec<RawCert>>>()
.expect("valid");
assert_eq!(certs.len(), 1);
let cert = &certs[0];
assert_eq!(cert.as_bytes(), testy);
assert_eq!(cert.primary_key().fingerprint(),
"3E8877C877274692975189F5D03F6F865226FE8B"
.parse().expect("valid"));
assert_eq!(cert.keys().map(|k| k.fingerprint()).collect::<Vec<_>>(),
vec![
"3E8877C877274692975189F5D03F6F865226FE8B"
.parse().expect("valid"),
"01F187575BD45644046564C149E2118166C92632"
.parse().expect("valid")
]);
assert_eq!(cert.keys().subkeys()
.map(|k| k.fingerprint()).collect::<Vec<_>>(),
vec![
"01F187575BD45644046564C149E2118166C92632"
.parse().expect("valid")
]);
assert_eq!(
cert.userids()
.map(|u| {
String::from_utf8_lossy(u.value()).into_owned()
})
.collect::<Vec<_>>(),
vec![ "Testy McTestface <testy@example.org>" ]);
}
}