sequoia_openpgp/packet_pile.rs
1use std::convert::TryFrom;
2use std::fmt;
3use std::vec;
4use std::iter::FromIterator;
5use std::iter::IntoIterator;
6
7use buffered_reader::BufferedReader;
8
9use crate::Result;
10use crate::Error;
11use crate::Packet;
12use crate::cert::Cert;
13use crate::packet::{self, Container};
14use crate::parse::PacketParserResult;
15use crate::parse::PacketParserBuilder;
16use crate::parse::Parse;
17use crate::parse::Cookie;
18
19/// An unstructured [packet] sequence.
20///
21/// To parse an OpenPGP packet stream into a `PacketPile`, you can use
22/// [`PacketParser`], [`PacketPileParser`], or
23/// [`PacketPile::from_file`] (or related routines).
24///
25/// [packet]: https://www.rfc-editor.org/rfc/rfc9580.html#section-4
26/// [`PacketParser`]: crate::parse::PacketParser
27/// [`PacketPileParser`]: crate::parse::PacketPileParser
28///
29/// You can also convert a [`Cert`] into a `PacketPile` using
30/// `PacketPile::from`. Unlike serializing a `Cert`, this does not
31/// drop any secret key material.
32///
33/// Normally, you'll want to convert the `PacketPile` to a `Cert` or a
34/// `Message`.
35///
36/// # Examples
37///
38/// This example shows how to modify packets in PacketPile using [`pathspec`]s.
39///
40/// [`pathspec`]: PacketPile::path_ref()
41///
42/// ```rust
43/// # use sequoia_openpgp as openpgp;
44/// use std::convert::TryFrom;
45/// use openpgp::{Packet, PacketPile};
46/// use openpgp::packet::signature::Signature4;
47/// use openpgp::packet::Signature;
48/// use openpgp::cert::prelude::*;
49/// use openpgp::parse::Parse;
50/// use openpgp::serialize::Serialize;
51/// use openpgp::policy::StandardPolicy;
52/// use openpgp::crypto::mpi;
53/// use openpgp::types::RevocationStatus;
54///
55/// # fn main() -> openpgp::Result<()> {
56/// let (cert, revocation) = CertBuilder::new().generate()?;
57///
58/// let mut buffer = Vec::new();
59/// cert.serialize(&mut buffer)?;
60/// let packet: Packet = revocation.into();
61/// packet.serialize(&mut buffer)?;
62///
63/// let policy = &StandardPolicy::new();
64///
65/// // Certificate is considered revoked because it is accompanied by its
66/// // revocation signature
67/// let pp: PacketPile = PacketPile::from_bytes(&buffer)?;
68/// let cert = Cert::try_from(pp)?;
69/// if let RevocationStatus::Revoked(_) = cert.revocation_status(policy, None) {
70/// // cert is considered revoked
71/// }
72/// # else {
73/// # unreachable!();
74/// # }
75///
76/// // Breaking the revocation signature changes certificate's status
77/// let mut pp: PacketPile = PacketPile::from_bytes(&buffer)?;
78/// if let Some(Packet::Signature(ref mut sig)) = pp.path_ref_mut(&[2]) {
79/// *sig = Signature4::new(
80/// sig.typ(),
81/// sig.pk_algo(),
82/// sig.hash_algo(),
83/// sig.hashed_area().clone(),
84/// sig.unhashed_area().clone(),
85/// *sig.digest_prefix(),
86/// // MPI is replaced with a dummy one
87/// mpi::Signature::RSA {
88/// s: mpi::MPI::from(vec![1, 2, 3])
89/// }).into();
90/// }
91///
92/// let cert = Cert::try_from(pp)?;
93/// if let RevocationStatus::NotAsFarAsWeKnow = cert.revocation_status(policy, None) {
94/// // revocation signature is broken and the cert is not revoked
95/// assert_eq!(cert.bad_signatures().count(), 1);
96/// }
97/// # else {
98/// # unreachable!();
99/// # }
100/// # Ok(())
101/// # }
102/// ```
103#[derive(PartialEq, Clone, Default)]
104pub struct PacketPile {
105 /// At the top level, we have a sequence of packets, which may be
106 /// containers.
107 top_level: Container,
108}
109
110assert_send_and_sync!(PacketPile);
111
112impl fmt::Debug for PacketPile {
113 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114 f.debug_struct("PacketPile")
115 .field("packets", &self.top_level.children_ref())
116 .finish()
117 }
118}
119
120impl<'a> Parse<'a, PacketPile> for PacketPile {
121 /// Deserializes the OpenPGP message stored in the file named by
122 /// `path`.
123 ///
124 /// Although this method is easier to use to parse a sequence of
125 /// OpenPGP packets than a [`PacketParser`] or a
126 /// [`PacketPileParser`], this interface buffers the whole message
127 /// in memory. Thus, the caller must be certain that the
128 /// *deserialized* message is not too large.
129 ///
130 /// Note: this interface *does* buffer the contents of packets.
131 ///
132 /// [`PacketParser`]: crate::parse::PacketParser
133 /// [`PacketPileParser`]: crate::parse::PacketPileParser
134 fn from_buffered_reader<R>(reader: R) -> Result<PacketPile>
135 where
136 R: BufferedReader<Cookie> + 'a,
137 {
138 PacketPile::from_cookie_reader(reader.into_boxed())
139 }
140}
141
142impl std::str::FromStr for PacketPile {
143 type Err = anyhow::Error;
144
145 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
146 Self::from_bytes(s.as_bytes())
147 }
148}
149
150impl From<Vec<Packet>> for PacketPile {
151 fn from(p: Vec<Packet>) -> Self {
152 PacketPile { top_level: Container::from(p) }
153 }
154}
155
156impl From<Packet> for PacketPile {
157 fn from(p: Packet) -> Self {
158 Self::from(vec![p])
159 }
160}
161
162impl FromIterator<Packet> for PacketPile {
163 fn from_iter<I: IntoIterator<Item=Packet>>(iter: I) -> Self {
164 Self::from(Vec::from_iter(iter))
165 }
166}
167
168impl From<PacketPile> for Vec<Packet> {
169 fn from(pp: PacketPile) -> Self {
170 pp.into_children().collect()
171 }
172}
173
174impl PacketPile {
175 /// Accessor for PacketPileParser.
176 pub(crate) fn top_level_mut(&mut self) -> &mut Container {
177 &mut self.top_level
178 }
179
180 /// Returns an error if operating on a non-container packet.
181 fn error() -> crate::Error {
182 crate::Error::InvalidOperation("Not a container packet".into())
183 }
184
185 /// Pretty prints the message to stderr.
186 ///
187 /// This function is primarily intended for debugging purposes.
188 #[cfg(test)]
189 pub fn pretty_print(&self) {
190 self.top_level.pretty_print(0);
191 }
192
193 /// Returns a reference to the packet at the location described by
194 /// `pathspec`.
195 ///
196 /// `pathspec` is a slice of the form `[0, 1, 2]`. Each element
197 /// is the index of packet in a container. Thus, the previous
198 /// path specification means: return the third child of the second
199 /// child of the first top-level packet. In other words, the
200 /// starred packet in the following tree:
201 ///
202 /// ```text
203 /// PacketPile
204 /// / | \
205 /// 0 1 2 ...
206 /// / \
207 /// / \
208 /// 0 1 ...
209 /// / | \ ...
210 /// 0 1 2
211 /// *
212 /// ```
213 ///
214 /// And, `[10]` means return the 11th top-level packet.
215 ///
216 /// Note: there is no packet at the root. Thus, the path `[]`
217 /// returns None.
218 ///
219 /// # Examples
220 ///
221 /// ```rust
222 /// # use sequoia_openpgp as openpgp;
223 /// # use openpgp::{Result, types::{CompressionAlgorithm, DataFormat},
224 /// # Packet, PacketPile, packet::Literal, packet::CompressedData};
225 /// # fn main() -> Result<()> {
226 /// # let mut lit = Literal::new(DataFormat::Unicode);
227 /// # lit.set_body(b"test".to_vec());
228 /// # let packets = vec![lit.into()];
229 /// let pile = PacketPile::from(packets);
230 ///
231 /// if let Some(packet) = pile.path_ref(&[0]) {
232 /// // There is a packet at this path.
233 /// }
234 /// # else {
235 /// # unreachable!();
236 /// # }
237 ///
238 /// if let None = pile.path_ref(&[0, 1, 2]) {
239 /// // But none here.
240 /// }
241 /// # else {
242 /// # unreachable!();
243 /// # }
244 /// # Ok(())
245 /// # }
246 /// ```
247 pub fn path_ref(&self, pathspec: &[usize]) -> Option<&Packet> {
248 let mut packet : Option<&Packet> = None;
249
250 let mut cont = Some(&self.top_level);
251 for i in pathspec {
252 if let Some(c) = cont.take() {
253 if let Some(children) = c.children_ref() {
254 if *i < children.len() {
255 let p = &children[*i];
256 packet = Some(p);
257 cont = p.container_ref();
258 continue;
259 }
260 }
261 }
262
263 return None;
264 }
265 packet
266 }
267
268 /// Returns a mutable reference to the packet at the location
269 /// described by `pathspec`.
270 ///
271 /// See the description of the `path_spec` for more details.
272 ///
273 /// # Examples
274 ///
275 /// ```rust
276 /// # use sequoia_openpgp as openpgp;
277 /// # use openpgp::{Result, types::{CompressionAlgorithm, DataFormat},
278 /// # Packet, PacketPile, packet::Literal, packet::CompressedData};
279 /// # fn main() -> Result<()> {
280 /// # let mut lit = Literal::new(DataFormat::Unicode);
281 /// # lit.set_body(b"test".to_vec());
282 /// # let packets = vec![lit.into()];
283 /// let mut pile = PacketPile::from(packets);
284 ///
285 /// if let Some(ref packet) = pile.path_ref_mut(&[0]) {
286 /// // There is a packet at this path.
287 /// }
288 /// # else {
289 /// # unreachable!();
290 /// # }
291 ///
292 /// if let None = pile.path_ref_mut(&[0, 1, 2]) {
293 /// // But none here.
294 /// }
295 /// # else {
296 /// # unreachable!();
297 /// # }
298 /// # Ok(())
299 /// # }
300 /// ```
301 pub fn path_ref_mut(&mut self, pathspec: &[usize]) -> Option<&mut Packet> {
302 let mut container = &mut self.top_level;
303
304 for (level, &i) in pathspec.iter().enumerate() {
305 let tmp = container;
306
307 let p = tmp.children_mut().and_then(|c| c.get_mut(i))?;
308
309 if level == pathspec.len() - 1 {
310 return Some(p)
311 }
312
313 container = p.container_mut().unwrap();
314 }
315
316 None
317 }
318
319 /// Replaces the specified packets at the location described by
320 /// `pathspec` with `packets`.
321 ///
322 /// If a packet is a container, the subtree rooted at the
323 /// container is removed.
324 ///
325 /// Note: the number of packets to remove need not match the
326 /// number of packets to insert.
327 ///
328 /// The removed packets are returned.
329 ///
330 /// If the path was invalid, then `Error::IndexOutOfRange` is
331 /// returned instead.
332 ///
333 /// # Examples
334 ///
335 /// ```rust
336 /// # use sequoia_openpgp as openpgp;
337 /// # use openpgp::{Result, types::{CompressionAlgorithm, DataFormat},
338 /// # Packet, PacketPile, packet::Literal, packet::CompressedData};
339 /// # fn main() -> Result<()> {
340 /// // A compressed data packet that contains a literal data packet.
341 /// let mut literal = Literal::new(DataFormat::Unicode);
342 /// literal.set_body(b"old".to_vec());
343 /// let mut compressed =
344 /// CompressedData::new(CompressionAlgorithm::Uncompressed);
345 /// compressed.container_mut().children_mut().unwrap().push(literal.into());
346 /// let mut pile = PacketPile::from(Packet::from(compressed));
347 ///
348 /// // Replace the literal data packet.
349 /// let mut literal = Literal::new(DataFormat::Unicode);
350 /// literal.set_body(b"new".to_vec());
351 /// pile.replace(
352 /// &[0, 0], 1,
353 /// [literal.into()].to_vec())?;
354 /// # if let Some(Packet::Literal(lit)) = pile.path_ref(&[0, 0]) {
355 /// # assert_eq!(lit.body(), &b"new"[..], "{:#?}", lit);
356 /// # } else {
357 /// # panic!("Unexpected packet!");
358 /// # }
359 /// # Ok(())
360 /// # }
361 /// ```
362 pub fn replace(&mut self, pathspec: &[usize], count: usize,
363 mut packets: Vec<Packet>)
364 -> Result<Vec<Packet>>
365 {
366 let mut container = &mut self.top_level;
367
368 for (level, &i) in pathspec.iter().enumerate() {
369 let tmp = container;
370
371 if level == pathspec.len() - 1 {
372 if tmp.children_ref().map(|c| i + count > c.len())
373 .unwrap_or(true)
374 {
375 return Err(Error::IndexOutOfRange.into());
376 }
377
378 // Out with the old...
379 let old = tmp.children_mut()
380 .expect("checked above")
381 .drain(i..i + count)
382 .collect::<Vec<Packet>>();
383 assert_eq!(old.len(), count);
384
385 // In with the new...
386
387 let mut tail = tmp.children_mut()
388 .expect("checked above")
389 .drain(i..)
390 .collect::<Vec<Packet>>();
391
392 tmp.children_mut().expect("checked above").append(&mut packets);
393 tmp.children_mut().expect("checked above").append(&mut tail);
394
395 return Ok(old)
396 }
397
398 if tmp.children_ref().map(|c| i >= c.len()).unwrap_or(true) {
399 return Err(Error::IndexOutOfRange.into());
400 }
401
402 match tmp.children_ref().expect("checked above")[i] {
403 // The structured container types.
404 Packet::CompressedData(_)
405 | Packet::SEIP(_)
406 => (), // Ok.
407 _ => return Err(Error::IndexOutOfRange.into()),
408 }
409 container =
410 tmp.children_mut().expect("checked above")[i].container_mut()
411 .expect("The above packets are structured containers");
412 }
413
414 Err(Error::IndexOutOfRange.into())
415 }
416
417 /// Returns an iterator over all the packet's descendants, in
418 /// depth-first order.
419 ///
420 /// ```rust
421 /// # use sequoia_openpgp as openpgp;
422 /// # use openpgp::{Result, types::{CompressionAlgorithm, DataFormat},
423 /// # Packet, PacketPile, packet::Literal, packet::Tag};
424 /// # use std::iter::Iterator;
425 /// # fn main() -> Result<()> {
426 /// let mut lit = Literal::new(DataFormat::Unicode);
427 /// lit.set_body(b"test".to_vec());
428 ///
429 /// let pile = PacketPile::from(vec![lit.into()]);
430 ///
431 /// for packet in pile.descendants() {
432 /// assert_eq!(packet.tag(), Tag::Literal);
433 /// }
434 /// # Ok(())
435 /// # }
436 /// ```
437 pub fn descendants(&self) -> packet::Iter {
438 self.top_level.descendants().expect("toplevel is a container")
439 }
440
441 /// Returns an iterator over the top-level packets.
442 ///
443 /// ```rust
444 /// # use sequoia_openpgp as openpgp;
445 /// # use openpgp::{Result, types::{CompressionAlgorithm, DataFormat},
446 /// # Packet, PacketPile, packet::Literal, packet::CompressedData};
447 /// # fn main() -> Result<()> {
448 /// let mut lit = Literal::new(DataFormat::Unicode);
449 /// lit.set_body(b"test".to_vec());
450 ///
451 /// let pile = PacketPile::from(vec![lit.into()]);
452 ///
453 /// assert_eq!(pile.children().len(), 1);
454 /// # Ok(())
455 /// # }
456 /// ```
457 pub fn children(&self)
458 -> impl Iterator<Item=&Packet> + ExactSizeIterator + Send + Sync
459 {
460 self.top_level.children().expect("toplevel is a container")
461 }
462
463 /// Returns an `IntoIter` over the top-level packets.
464 ///
465 /// ```rust
466 /// # use sequoia_openpgp as openpgp;
467 /// # use openpgp::{Result, types::{CompressionAlgorithm, DataFormat},
468 /// # Packet, PacketPile, packet::Literal, packet::Tag};
469 /// # fn main() -> Result<()> {
470 /// let mut lit = Literal::new(DataFormat::Unicode);
471 /// lit.set_body(b"test".to_vec());
472 ///
473 /// let pile = PacketPile::from(vec![lit.into()]);
474 ///
475 /// for packet in pile.into_children() {
476 /// assert_eq!(packet.tag(), Tag::Literal);
477 /// }
478 /// # Ok(())
479 /// # }
480 /// ```
481 pub fn into_children(self)
482 -> impl Iterator<Item=Packet> + ExactSizeIterator + Send + Sync
483 {
484 self.top_level.into_children().expect("toplevel is a container")
485 }
486
487
488 pub(crate) fn from_cookie_reader<'a>(bio: Box<dyn BufferedReader<Cookie> + 'a>)
489 -> Result<PacketPile> {
490 PacketParserBuilder::from_cookie_reader(bio)?
491 .buffer_unread_content()
492 .into_packet_pile()
493 }
494}
495
496impl From<Cert> for PacketPile {
497 /// Converts the `Cert` into a `PacketPile`.
498 ///
499 /// If any packets include secret key material, that secret key
500 /// material is included in the resulting `PacketPile`. In
501 /// contrast, when serializing a `Cert`, or converting a cert to
502 /// packets with [`Cert::into_packets`], the secret key material
503 /// not included.
504 ///
505 /// Note: This will change in sequoia-openpgp version 2, which
506 /// will harmonize the behavior and not include secret key
507 /// material.
508 // XXXv2: Drop the note in the doc comment and mentioned it in the
509 // release notes.
510 fn from(cert: Cert) -> PacketPile {
511 #[allow(deprecated)]
512 PacketPile::from(cert.into_packets().collect::<Vec<Packet>>())
513 }
514}
515
516impl<'a> TryFrom<PacketParserResult<'a>> for PacketPile {
517 type Error = anyhow::Error;
518
519 /// Reads all the packets from a `PacketParser`, and turns them
520 /// into a message.
521 ///
522 /// Note: this assumes that `ppr` points to a top-level packet.
523 fn try_from(ppr: PacketParserResult<'a>)
524 -> Result<PacketPile>
525 {
526 // Things are not going to work out if we don't start with a
527 // top-level packet. We should only pop until
528 // ppo.recursion_depth and leave the rest of the message, but
529 // it is hard to imagine that that is what the caller wants.
530 // Instead of hiding that error, fail fast.
531 if let PacketParserResult::Some(ref pp) = ppr {
532 if pp.recursion_depth() != 0 {
533 return Err(Error::InvalidOperation(
534 format!("Expected top-level packet, \
535 but the parser is at level {}",
536 pp.recursion_depth())).into());
537 }
538 }
539
540 // Create a top-level container.
541 let mut top_level = Container::default();
542
543 let mut last_position = 0;
544
545 if ppr.is_eof() {
546 // Empty message.
547 return Ok(PacketPile::from(Vec::new()));
548 }
549 let mut pp = ppr.unwrap();
550
551 'outer: loop {
552 let recursion_depth = pp.recursion_depth();
553 let (mut packet, mut ppr) = pp.recurse()?;
554 let mut position = recursion_depth as isize;
555
556 let mut relative_position : isize = position - last_position;
557 assert!(relative_position <= 1);
558
559 // Find the right container for `packet`.
560 let mut container = &mut top_level;
561 // If we recurse, don't create the new container here.
562 for _ in 0..(position - if relative_position > 0 { 1 } else { 0 }) {
563 // Do a little dance to prevent container from
564 // being reborrowed and preventing us from
565 // assigning to it.
566 let tmp = container;
567 let packets_len =
568 tmp.children_ref().ok_or_else(Self::error)?.len();
569 let p = &mut tmp.children_mut()
570 .ok_or_else(Self::error)?
571 [packets_len - 1];
572
573 container = p.container_mut().unwrap();
574 }
575
576 if relative_position < 0 {
577 relative_position = 0;
578 }
579
580 // If next packet will be inserted in the same container
581 // or the current container's child, we don't need to walk
582 // the tree from the root.
583 loop {
584 if relative_position == 1 {
585 // Create a new container.
586 let tmp = container;
587 let i =
588 tmp.children_ref().ok_or_else(Self::error)?.len() - 1;
589 container = tmp.children_mut()
590 .ok_or_else(Self::error)?
591 [i].container_mut().unwrap();
592 }
593
594 container.children_mut().unwrap().push(packet);
595
596 if ppr.is_eof() {
597 break 'outer;
598 }
599
600 pp = ppr.unwrap();
601
602 last_position = position;
603 position = pp.recursion_depth() as isize;
604 relative_position = position - last_position;
605 if position < last_position {
606 // There was a pop, we need to restart from the
607 // root.
608 break;
609 }
610
611 let recursion_depth = pp.recursion_depth();
612 let (packet_, ppr_) = pp.recurse()?;
613 packet = packet_;
614 ppr = ppr_;
615 assert_eq!(position, recursion_depth as isize);
616 }
617 }
618
619 Ok(PacketPile { top_level })
620 }
621}
622
623impl<'a> PacketParserBuilder<'a> {
624 /// Finishes configuring the `PacketParser` and returns a fully
625 /// parsed message.
626 ///
627 /// Note: calling this function does not change the default
628 /// settings. Thus, by default, the content of packets will *not*
629 /// be buffered.
630 ///
631 /// Note: to avoid denial-of-service attacks, the `PacketParser`
632 /// interface should be preferred unless the size of the message
633 /// is known to fit in memory.
634 ///
635 /// # Examples
636 ///
637 /// ```rust
638 /// # use sequoia_openpgp as openpgp;
639 /// # use openpgp::Result;
640 /// # use openpgp::PacketPile;
641 /// # use openpgp::parse::{Parse, PacketParser, PacketParserBuilder};
642 /// # f(include_bytes!("../tests/data/keys/public-key.pgp"));
643 /// #
644 /// # fn f(message_data: &[u8]) -> Result<PacketPile> {
645 /// let message = PacketParserBuilder::from_bytes(message_data)?
646 /// .buffer_unread_content()
647 /// .into_packet_pile()?;
648 /// # return Ok(message);
649 /// # }
650 /// ```
651 pub fn into_packet_pile(self) -> Result<PacketPile> {
652 PacketPile::try_from(self.build()?)
653 }
654}
655
656#[cfg(test)]
657mod test {
658 use super::*;
659
660 use crate::types::CompressionAlgorithm;
661 use crate::types::DataFormat::Unicode;
662 use crate::packet::Literal;
663 use crate::packet::CompressedData;
664 use crate::packet::seip::SEIP1;
665 use crate::packet::Tag;
666 use crate::parse::Parse;
667
668 #[test]
669 fn deserialize_test_1 () {
670 // XXX: This test should be more thorough. Right now, we mostly
671 // just rely on the fact that an assertion is not thrown.
672
673 // A flat message.
674 let pile = PacketPile::from_bytes(crate::tests::key("public-key.pgp"))
675 .unwrap();
676 eprintln!("PacketPile has {} top-level packets.",
677 pile.children().len());
678 eprintln!("PacketPile: {:?}", pile);
679
680 let mut count = 0;
681 for (i, p) in pile.descendants().enumerate() {
682 eprintln!("{}: {:?}", i, p);
683 count += 1;
684 }
685
686 assert_eq!(count, 61);
687 }
688
689 #[cfg(feature = "compression-deflate")]
690 #[test]
691 fn deserialize_test_2 () {
692 // A message containing a compressed packet that contains a
693 // literal packet.
694 let pile = PacketPile::from_bytes(
695 crate::tests::message("compressed-data-algo-1.pgp")).unwrap();
696 eprintln!("PacketPile has {} top-level packets.",
697 pile.children().len());
698 eprintln!("PacketPile: {:?}", pile);
699
700 let mut count = 0;
701 for (i, p) in pile.descendants().enumerate() {
702 eprintln!("{}: {:?}", i, p);
703 count += 1;
704 }
705 assert_eq!(count, 2);
706 }
707
708 #[cfg(feature = "compression-deflate")]
709 #[test]
710 fn deserialize_test_3 () {
711 let pile =
712 PacketPile::from_bytes(crate::tests::message("signed.pgp")).unwrap();
713 eprintln!("PacketPile has {} top-level packets.",
714 pile.children().len());
715 eprintln!("PacketPile: {:?}", pile);
716
717 let mut count = 0;
718 for (i, p) in pile.descendants().enumerate() {
719 count += 1;
720 eprintln!("{}: {:?}", i, p);
721 }
722 // We expect 6 packets.
723 assert_eq!(count, 6);
724 }
725
726 // dkg's key contains packets from different OpenPGP
727 // implementations. And, it even includes some v3 signatures.
728 //
729 // lutz's key is a v3 key.
730 #[test]
731 fn torture() {
732 use std::convert::TryInto;
733 use crate::parse::PacketPileParser;
734
735 let data = crate::tests::key("dkg.pgp");
736 let mut ppp: PacketPileParser =
737 PacketParserBuilder::from_bytes(data).unwrap()
738 //.trace()
739 .buffer_unread_content()
740 .try_into().unwrap();
741
742 while ppp.packet().is_ok() {
743 ppp.recurse().unwrap();
744 }
745 let pile = ppp.finish();
746 //pile.pretty_print();
747 assert_eq!(pile.children().len(), 1450);
748
749 let data = crate::tests::key("lutz.pgp");
750 let mut ppp: PacketPileParser =
751 PacketParserBuilder::from_bytes(data).unwrap()
752 //.trace()
753 .buffer_unread_content()
754 .try_into().unwrap();
755
756 while let Ok(pp) = ppp.packet().as_ref() {
757 eprintln!("{:?}", pp);
758 ppp.recurse().unwrap();
759 }
760 let pile = ppp.finish();
761 pile.pretty_print();
762 assert_eq!(pile.children().len(), 77);
763 }
764
765 #[cfg(feature = "compression-deflate")]
766 #[test]
767 fn compression_quine_test_1 () {
768 // Use the PacketPile::from_file interface to parse an OpenPGP
769 // quine.
770 let max_recursion_depth = 128;
771 let pile = PacketParserBuilder::from_bytes(
772 crate::tests::message("compression-quine.pgp")).unwrap()
773 .max_recursion_depth(max_recursion_depth)
774 .into_packet_pile().unwrap();
775
776 let mut count = 0;
777 for (i, p) in pile.descendants().enumerate() {
778 count += 1;
779 if false {
780 eprintln!("{}: p: {:?}", i, p);
781 }
782 }
783
784 assert_eq!(count, 1 + max_recursion_depth);
785 }
786
787 #[cfg(feature = "compression-deflate")]
788 #[test]
789 fn compression_quine_test_2 () {
790 // Use the iterator interface to parse an OpenPGP quine.
791 let max_recursion_depth = 255;
792 let mut ppr : PacketParserResult
793 = PacketParserBuilder::from_bytes(
794 crate::tests::message("compression-quine.pgp")).unwrap()
795 .max_recursion_depth(max_recursion_depth)
796 .build().unwrap();
797
798 let mut count = 0;
799 loop {
800 if let PacketParserResult::Some(pp2) = ppr {
801 count += 1;
802
803 let packet_depth = pp2.recursion_depth();
804 let pp2 = pp2.recurse().unwrap().1;
805 assert_eq!(packet_depth, count - 1);
806 if pp2.is_some() {
807 assert_eq!(pp2.as_ref().unwrap().recursion_depth(), count);
808 }
809 ppr = pp2;
810 } else {
811 break;
812 }
813 }
814 assert_eq!(count, 1 + max_recursion_depth as isize);
815 }
816
817 #[cfg(feature = "compression-deflate")]
818 #[test]
819 fn consume_content_1 () {
820 use std::io::Read;
821 use crate::parse::PacketParser;
822 // A message containing a compressed packet that contains a
823 // literal packet. When we read some of the compressed
824 // packet, we expect recurse() to not recurse.
825
826 let ppr = PacketParserBuilder::from_bytes(
827 crate::tests::message("compressed-data-algo-1.pgp")).unwrap()
828 .buffer_unread_content()
829 .build().unwrap();
830
831 let mut pp = ppr.unwrap();
832 if let Packet::CompressedData(_) = pp.packet {
833 } else {
834 panic!("Expected a compressed packet!");
835 }
836
837 // Read some of the body of the compressed packet.
838 let mut data = [0u8; 1];
839 let amount = pp.read(&mut data).unwrap();
840 assert_eq!(amount, 1);
841
842 // recurse should now not recurse. Since there is nothing
843 // following the compressed packet, ppr should be EOF.
844 let (packet, ppr) = pp.next().unwrap();
845 assert!(ppr.is_eof());
846
847 // Get the rest of the content and put the initial byte that
848 // we stole back.
849 let mut content = packet.processed_body().unwrap().to_vec();
850 content.insert(0, data[0]);
851
852 let ppr = PacketParser::from_bytes(&content).unwrap();
853 let pp = ppr.unwrap();
854 if let Packet::Literal(_) = pp.packet {
855 } else {
856 panic!("Expected a literal packet!");
857 }
858
859 // And we're done...
860 let ppr = pp.next().unwrap().1;
861 assert!(ppr.is_eof());
862 }
863
864 #[test]
865 fn path_ref() {
866 // 0: SEIP
867 // 0: CompressedData
868 // 0: Literal("one")
869 // 1: Literal("two")
870 // 2: Literal("three")
871 // 3: Literal("four")
872 let mut packets : Vec<Packet> = Vec::new();
873
874 let text = [ &b"one"[..], &b"two"[..],
875 &b"three"[..], &b"four"[..] ].to_vec();
876
877 let mut cd = CompressedData::new(CompressionAlgorithm::Uncompressed);
878 for t in text.iter() {
879 let mut lit = Literal::new(Unicode);
880 lit.set_body(t.to_vec());
881 cd = cd.push(lit.into())
882 }
883
884 let mut seip = SEIP1::new();
885 seip.container_mut().children_mut().unwrap().push(cd.into());
886 packets.push(seip.into());
887
888 eprintln!("{:#?}", packets);
889
890 let mut pile = PacketPile::from(packets);
891
892 assert_eq!(pile.path_ref(&[ 0 ]).unwrap().tag(), Tag::SEIP);
893 assert_eq!(pile.path_ref_mut(&[ 0 ]).unwrap().tag(), Tag::SEIP);
894 assert_eq!(pile.path_ref(&[ 0, 0 ]).unwrap().tag(),
895 Tag::CompressedData);
896 assert_eq!(pile.path_ref_mut(&[ 0, 0 ]).unwrap().tag(),
897 Tag::CompressedData);
898
899 for (i, t) in text.into_iter().enumerate() {
900 assert_eq!(pile.path_ref(&[ 0, 0, i ]).unwrap().tag(),
901 Tag::Literal);
902 assert_eq!(pile.path_ref_mut(&[ 0, 0, i ]).unwrap().tag(),
903 Tag::Literal);
904
905 let packet = pile.path_ref(&[ 0, 0, i ]).unwrap();
906 if let Packet::Literal(l) = packet {
907 assert_eq!(l.body(), t);
908 } else {
909 panic!("Expected literal, got: {:?}", packet);
910 }
911 let packet = pile.path_ref_mut(&[ 0, 0, i ]).unwrap();
912 if let Packet::Literal(l) = packet {
913 assert_eq!(l.body(), t);
914 } else {
915 panic!("Expected literal, got: {:?}", packet);
916 }
917 }
918
919 // Try a few out of bounds accesses.
920 assert!(pile.path_ref(&[ 0, 0, 4 ]).is_none());
921 assert!(pile.path_ref_mut(&[ 0, 0, 4 ]).is_none());
922
923 assert!(pile.path_ref(&[ 0, 0, 5 ]).is_none());
924 assert!(pile.path_ref_mut(&[ 0, 0, 5 ]).is_none());
925
926 assert!(pile.path_ref(&[ 0, 1 ]).is_none());
927 assert!(pile.path_ref_mut(&[ 0, 1 ]).is_none());
928
929 assert!(pile.path_ref(&[ 0, 2 ]).is_none());
930 assert!(pile.path_ref_mut(&[ 0, 2 ]).is_none());
931
932 assert!(pile.path_ref(&[ 1 ]).is_none());
933 assert!(pile.path_ref_mut(&[ 1 ]).is_none());
934
935 assert!(pile.path_ref(&[ 2 ]).is_none());
936 assert!(pile.path_ref_mut(&[ 2 ]).is_none());
937
938 assert!(pile.path_ref(&[ 0, 1, 0 ]).is_none());
939 assert!(pile.path_ref_mut(&[ 0, 1, 0 ]).is_none());
940
941 assert!(pile.path_ref(&[ 0, 2, 0 ]).is_none());
942 assert!(pile.path_ref_mut(&[ 0, 2, 0 ]).is_none());
943 }
944
945 #[test]
946 fn replace() {
947 // 0: Literal("one")
948 // =>
949 // 0: Literal("two")
950 let mut one = Literal::new(Unicode);
951 one.set_body(b"one".to_vec());
952 let mut two = Literal::new(Unicode);
953 two.set_body(b"two".to_vec());
954 let mut packets : Vec<Packet> = Vec::new();
955 packets.push(one.into());
956
957 assert!(packets.iter().map(|p| p.tag()).collect::<Vec<Tag>>()
958 == [ Tag::Literal ]);
959
960 let mut pile = PacketPile::from(packets.clone());
961 pile.replace(
962 &[ 0 ], 1,
963 [ two.into()
964 ].to_vec()).unwrap();
965
966 let children = pile.into_children().collect::<Vec<Packet>>();
967 assert_eq!(children.len(), 1, "{:#?}", children);
968 if let Packet::Literal(ref literal) = children[0] {
969 assert_eq!(literal.body(), &b"two"[..], "{:#?}", literal);
970 } else {
971 panic!("WTF");
972 }
973
974 // We start with four packets, and replace some of them with
975 // up to 3 packets.
976 let initial
977 = [ &b"one"[..], &b"two"[..], &b"three"[..], &b"four"[..] ].to_vec();
978 let inserted
979 = [ &b"a"[..], &b"b"[..], &b"c"[..] ].to_vec();
980
981 let mut packets : Vec<Packet> = Vec::new();
982 for text in initial.iter() {
983 let mut lit = Literal::new(Unicode);
984 lit.set_body(text.to_vec());
985 packets.push(lit.into())
986 }
987
988 for start in 0..initial.len() + 1 {
989 for delete in 0..initial.len() - start + 1 {
990 for insert in 0..inserted.len() + 1 {
991 let mut pile = PacketPile::from(packets.clone());
992
993 let mut replacement : Vec<Packet> = Vec::new();
994 for &text in inserted[0..insert].iter() {
995 let mut lit = Literal::new(Unicode);
996 lit.set_body(text.to_vec());
997 replacement.push(lit.into());
998 }
999
1000 pile.replace(&[ start ], delete, replacement).unwrap();
1001
1002 let values = pile
1003 .children()
1004 .map(|p| {
1005 if let Packet::Literal(ref literal) = p {
1006 literal.body()
1007 } else {
1008 panic!("Expected a literal packet, got: {:?}", p);
1009 }
1010 })
1011 .collect::<Vec<&[u8]>>();
1012
1013 assert_eq!(values.len(), initial.len() - delete + insert);
1014
1015 assert_eq!(values[..start],
1016 initial[..start]);
1017 assert_eq!(values[start..start + insert],
1018 inserted[..insert]);
1019 assert_eq!(values[start + insert..],
1020 initial[start + delete..]);
1021 }
1022 }
1023 }
1024
1025
1026 // Like above, but the packets to replace are not at the
1027 // top-level, but in a compressed data packet.
1028
1029 let initial
1030 = [ &b"one"[..], &b"two"[..], &b"three"[..], &b"four"[..] ].to_vec();
1031 let inserted
1032 = [ &b"a"[..], &b"b"[..], &b"c"[..] ].to_vec();
1033
1034 let mut cd = CompressedData::new(CompressionAlgorithm::Uncompressed);
1035 for l in initial.iter() {
1036 let mut lit = Literal::new(Unicode);
1037 lit.set_body(l.to_vec());
1038 cd = cd.push(lit.into());
1039 }
1040
1041 for start in 0..initial.len() + 1 {
1042 for delete in 0..initial.len() - start + 1 {
1043 for insert in 0..inserted.len() + 1 {
1044 let mut pile = PacketPile::from(
1045 vec![ cd.clone().into() ]);
1046
1047 let mut replacement : Vec<Packet> = Vec::new();
1048 for &text in inserted[0..insert].iter() {
1049 let mut lit = Literal::new(Unicode);
1050 lit.set_body(text.to_vec());
1051 replacement.push(lit.into());
1052 }
1053
1054 pile.replace(&[ 0, start ], delete, replacement).unwrap();
1055
1056 let top_level = pile.children().collect::<Vec<&Packet>>();
1057 assert_eq!(top_level.len(), 1);
1058
1059 let values = top_level[0]
1060 .children().unwrap()
1061 .map(|p| {
1062 if let Packet::Literal(ref literal) = p {
1063 literal.body()
1064 } else {
1065 panic!("Expected a literal packet, got: {:?}", p);
1066 }
1067 })
1068 .collect::<Vec<&[u8]>>();
1069
1070 assert_eq!(values.len(), initial.len() - delete + insert);
1071
1072 assert_eq!(values[..start],
1073 initial[..start]);
1074 assert_eq!(values[start..start + insert],
1075 inserted[..insert]);
1076 assert_eq!(values[start + insert..],
1077 initial[start + delete..]);
1078 }
1079 }
1080 }
1081
1082 // Make sure out-of-range accesses error out.
1083 let mut one = Literal::new(Unicode);
1084 one.set_body(b"one".to_vec());
1085 let mut packets : Vec<Packet> = Vec::new();
1086 packets.push(one.into());
1087 let mut pile = PacketPile::from(packets.clone());
1088
1089 assert!(pile.replace(&[ 1 ], 0, Vec::new()).is_ok());
1090 assert!(pile.replace(&[ 2 ], 0, Vec::new()).is_err());
1091 assert!(pile.replace(&[ 0 ], 2, Vec::new()).is_err());
1092 assert!(pile.replace(&[ 0, 0 ], 0, Vec::new()).is_err());
1093 assert!(pile.replace(&[ 0, 1 ], 0, Vec::new()).is_err());
1094
1095 // Try the same thing, but with a container.
1096 let mut packets : Vec<Packet> = Vec::new();
1097 packets.push(CompressedData::new(CompressionAlgorithm::Uncompressed)
1098 .into());
1099 let mut pile = PacketPile::from(packets.clone());
1100
1101 assert!(pile.replace(&[ 1 ], 0, Vec::new()).is_ok());
1102 assert!(pile.replace(&[ 2 ], 0, Vec::new()).is_err());
1103 assert!(pile.replace(&[ 0 ], 2, Vec::new()).is_err());
1104 // Since this is a container, this should be okay.
1105 assert!(pile.replace(&[ 0, 0 ], 0, Vec::new()).is_ok());
1106 assert!(pile.replace(&[ 0, 1 ], 0, Vec::new()).is_err());
1107 }
1108}