sequoia_openpgp/serialize/stream/writer/
mod.rs

1//! Stackable writers.
2
3#[cfg(feature = "compression-bzip2")]
4mod writer_bzip2;
5#[cfg(feature = "compression-bzip2")]
6pub use self::writer_bzip2::BZ;
7#[cfg(feature = "compression-deflate")]
8mod writer_deflate;
9#[cfg(feature = "compression-deflate")]
10pub use self::writer_deflate::{ZIP, ZLIB};
11
12use std::fmt;
13use std::io;
14
15use crate::armor;
16use crate::crypto::{aead, symmetric};
17use crate::types::{
18    AEADAlgorithm,
19    SymmetricAlgorithm,
20};
21use crate::{
22    Profile,
23    Result,
24    crypto::SessionKey,
25};
26use super::{Message, Cookie};
27
28impl<'a> Message<'a> {
29    pub(super) fn from(bs: BoxStack<'a, Cookie>) -> Self {
30        Message(bs)
31    }
32
33    pub(super) fn as_ref(&self) -> &BoxStack<'a, Cookie> {
34        &self.0
35    }
36
37    pub(super) fn as_mut(&mut self) -> &mut BoxStack<'a, Cookie> {
38        &mut self.0
39    }
40}
41
42impl<'a> io::Write for Message<'a> {
43    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
44        self.0.write(buf)
45    }
46
47    fn flush(&mut self) -> io::Result<()> {
48        self.0.flush()
49    }
50}
51
52impl<'a> From<Message<'a>> for BoxStack<'a, Cookie> {
53    fn from(s: Message<'a>) -> Self {
54        s.0
55    }
56}
57
58pub(crate) type BoxStack<'a, C> = Box<dyn Stackable<'a, C> + Send + Sync + 'a>;
59
60/// Makes a writer stackable and provides convenience functions.
61pub(crate) trait Stackable<'a, C> : io::Write + fmt::Debug {
62    /// Recovers the inner stackable.
63    ///
64    /// This can fail if the current `Stackable` has buffered data
65    /// that hasn't been written to the underlying `Stackable`.
66    fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>>;
67
68    /// Pops the stackable from the stack, detaching it.
69    ///
70    /// Returns the detached stack.
71    ///
72    /// Note: Only the Signer implements this interface.
73    fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>>;
74
75    /// Sets the inner stackable.
76    ///
77    /// Note: Only the Signer implements this interface.
78    fn mount(&mut self, new: BoxStack<'a, C>);
79
80    /// Returns a mutable reference to the inner `Writer`, if
81    /// any.
82    ///
83    /// It is a very bad idea to write any data from the inner
84    /// `Writer`, but it can sometimes be useful to get the cookie.
85    fn inner_mut(&mut self) -> Option<&mut (dyn Stackable<'a, C> + Send + Sync)>;
86
87    /// Returns a reference to the inner `Writer`.
88    fn inner_ref(&self) -> Option<&(dyn Stackable<'a, C> + Send + Sync)>;
89
90    /// Sets the cookie and returns the old value.
91    #[allow(dead_code)]
92    fn cookie_set(&mut self, cookie: C) -> C;
93
94    /// Returns a reference to the cookie.
95    fn cookie_ref(&self) -> &C;
96
97    /// Returns a mutable reference to the cookie.
98    #[allow(dead_code)]
99    fn cookie_mut(&mut self) -> &mut C;
100
101    /// Returns the number of bytes written to this filter.
102    fn position(&self) -> u64;
103
104    /// Writes a byte.
105    fn write_u8(&mut self, b: u8) -> io::Result<()> {
106        self.write_all(&[b])
107    }
108}
109
110/// Make a `Box<Stackable>` look like a Stackable.
111impl <'a, C> Stackable<'a, C> for BoxStack<'a, C> {
112    fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>> {
113        (*self).into_inner()
114    }
115    /// Recovers the inner stackable.
116    fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>> {
117        self.as_mut().pop()
118    }
119    /// Sets the inner stackable.
120    fn mount(&mut self, new: BoxStack<'a, C>) {
121        self.as_mut().mount(new);
122    }
123    fn inner_mut(&mut self) -> Option<&mut (dyn Stackable<'a, C> + Send + Sync)> {
124        self.as_mut().inner_mut()
125    }
126    fn inner_ref(&self) -> Option<&(dyn Stackable<'a, C> + Send + Sync)> {
127        self.as_ref().inner_ref()
128    }
129    fn cookie_set(&mut self, cookie: C) -> C {
130        self.as_mut().cookie_set(cookie)
131    }
132    fn cookie_ref(&self) -> &C {
133        self.as_ref().cookie_ref()
134    }
135    fn cookie_mut(&mut self) -> &mut C {
136        self.as_mut().cookie_mut()
137    }
138    fn position(&self) -> u64 {
139        self.as_ref().position()
140    }
141}
142
143/// Maps a function over the stack of writers.
144#[allow(dead_code)]
145pub(crate) fn map<C, F, T>(head: &(dyn Stackable<C> + Send + Sync),
146                           mut fun: F) -> Option<T>
147where
148    F: FnMut(&(dyn Stackable<C> + Send + Sync)) -> Option<T>,
149{
150    let mut ow = Some(head);
151    while let Some(w) = ow {
152        if let Some(r) = fun(w) {
153            return Some(r);
154        }
155        ow = w.inner_ref()
156    }
157
158    None
159}
160
161/// Maps a function over the stack of mutable writers.
162#[allow(dead_code)]
163pub(crate) fn map_mut<C, F, T>(head: &mut (dyn Stackable<C> + Send + Sync),
164                               mut fun: F) -> Option<T>
165where F: FnMut(&mut (dyn Stackable<C> + Send + Sync)) -> Option<T>
166{
167    let mut ow = Some(head);
168    while let Some(w) = ow {
169        if let Some(r) = fun(w) {
170            return Some(r);
171        }
172        ow = w.inner_mut()
173    }
174
175    None
176}
177
178/// Dumps the writer stack.
179#[allow(dead_code)]
180pub(crate) fn dump<C>(head: &(dyn Stackable<C> + Send + Sync)) {
181    let mut depth = 0;
182    map(head, |w| {
183        eprintln!("{}: {:?}", depth, w);
184        depth += 1;
185        Some(())
186    });
187}
188
189/// The identity writer just relays anything written.
190pub struct Identity<'a, C> {
191    inner: Option<BoxStack<'a, C>>,
192    cookie: C,
193}
194assert_send_and_sync!(Identity<'_, C> where C);
195
196impl<'a> Identity<'a, Cookie> {
197    /// Makes an identity writer.
198    pub fn new(inner: Message<'a>, cookie: Cookie)
199                  -> Message<'a> {
200        Message::from(Box::new(Self{inner: Some(inner.into()), cookie }))
201    }
202}
203
204impl<'a, C> fmt::Debug for Identity<'a, C> {
205    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
206        f.debug_struct("Identity")
207            .field("inner", &self.inner)
208            .finish()
209    }
210}
211
212impl<'a, C> io::Write for Identity<'a, C> {
213    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
214        let writer = self.inner.as_mut()
215            .ok_or_else(|| io::Error::new(io::ErrorKind::BrokenPipe,
216                                          "Writer is finalized."))?;
217        writer.write(buf)
218    }
219
220    fn flush(&mut self) -> io::Result<()> {
221        let writer = self.inner.as_mut()
222            .ok_or_else(|| io::Error::new(io::ErrorKind::BrokenPipe,
223                                          "Writer is finalized."))?;
224        writer.flush()
225    }
226}
227
228impl<'a, C> Stackable<'a, C> for Identity<'a, C> {
229    /// Recovers the inner stackable.
230    fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>> {
231        Ok(self.inner)
232    }
233    /// Recovers the inner stackable.
234    fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>> {
235        Ok(self.inner.take())
236    }
237    /// Sets the inner stackable.
238    fn mount(&mut self, new: BoxStack<'a, C>) {
239        self.inner = Some(new);
240    }
241    fn inner_ref(&self) -> Option<&(dyn Stackable<'a, C> + Send + Sync)> {
242        if let Some(ref i) = self.inner {
243            Some(i)
244        } else {
245            None
246        }
247    }
248    fn inner_mut(&mut self) -> Option<&mut (dyn Stackable<'a, C> + Send + Sync)> {
249        if let Some(ref mut i) = self.inner {
250            Some(i)
251        } else {
252            None
253        }
254    }
255    fn cookie_set(&mut self, cookie: C) -> C {
256        ::std::mem::replace(&mut self.cookie, cookie)
257    }
258    fn cookie_ref(&self) -> &C {
259        &self.cookie
260    }
261    fn cookie_mut(&mut self) -> &mut C {
262        &mut self.cookie
263    }
264    fn position(&self) -> u64 {
265        self.inner.as_ref().map(|i| i.position()).unwrap_or(0)
266    }
267}
268
269/// Generic writer wrapping `io::Write`.
270pub struct Generic<W: io::Write + Send + Sync, C> {
271    inner: W,
272    cookie: C,
273    position: u64,
274}
275assert_send_and_sync!(Generic<W, C> where W: io::Write, C);
276
277impl<'a, W: 'a + io::Write + Send + Sync> Generic<W, Cookie> {
278    /// Wraps an `io::Write`r.
279    pub fn new(inner: W, cookie: Cookie) -> Message<'a> {
280        Message::from(Box::new(Self::new_unboxed(inner, cookie)))
281    }
282
283    fn new_unboxed(inner: W, cookie: Cookie) -> Self {
284        Generic {
285            inner,
286            cookie,
287            position: 0,
288        }
289    }
290}
291
292impl<W: io::Write + Send + Sync, C> fmt::Debug for Generic<W, C> {
293    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
294        f.debug_struct("writer::Generic")
295            .finish()
296    }
297}
298
299impl<W: io::Write + Send + Sync, C> io::Write for Generic<W, C> {
300    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
301        match self.inner.write(bytes) {
302            Ok(n) => {
303                self.position += n as u64;
304                Ok(n)
305            },
306            Err(e) => Err(e),
307        }
308    }
309
310    fn flush(&mut self) -> io::Result<()> {
311        self.inner.flush()
312    }
313}
314
315impl<'a, W: io::Write + Send + Sync, C> Stackable<'a, C> for Generic<W, C> {
316    /// Recovers the inner stackable.
317    fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>> {
318        Ok(None)
319    }
320    /// Recovers the inner stackable.
321    fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>> {
322        Ok(None)
323    }
324    /// Sets the inner stackable.
325    fn mount(&mut self, _new: BoxStack<'a, C>) {
326    }
327    fn inner_mut(&mut self) -> Option<&mut (dyn Stackable<'a, C> + Send + Sync)> {
328        // If you use Generic to wrap an io::Writer, and you know that
329        // the io::Writer's inner is also a Stackable, then return a
330        // reference to the innermost Stackable in your
331        // implementation.  See e.g. writer::ZLIB.
332        None
333    }
334    fn inner_ref(&self) -> Option<&(dyn Stackable<'a, C> + Send + Sync)> {
335        // If you use Generic to wrap an io::Writer, and you know that
336        // the io::Writer's inner is also a Stackable, then return a
337        // reference to the innermost Stackable in your
338        // implementation.  See e.g. writer::ZLIB.
339        None
340    }
341    fn cookie_set(&mut self, cookie: C) -> C {
342        ::std::mem::replace(&mut self.cookie, cookie)
343    }
344    fn cookie_ref(&self) -> &C {
345        &self.cookie
346    }
347    fn cookie_mut(&mut self) -> &mut C {
348        &mut self.cookie
349    }
350    fn position(&self) -> u64 {
351        self.position
352    }
353}
354
355
356/// Armoring writer.
357pub struct Armorer<'a, C: 'a> {
358    inner: Generic<armor::Writer<BoxStack<'a, C>>, C>,
359}
360assert_send_and_sync!(Armorer<'_, C> where C);
361
362impl<'a> Armorer<'a, Cookie> {
363    /// Makes an armoring writer.
364    pub fn new<I, K, V>(inner: Message<'a>, cookie: Cookie,
365                        kind: armor::Kind, headers: I)
366                        -> Result<Message<'a>>
367        where I: IntoIterator<Item = (K, V)>,
368              K: AsRef<str>,
369              V: AsRef<str>,
370    {
371        Ok(Message::from(Box::new(Armorer {
372            inner: Generic::new_unboxed(
373                armor::Writer::with_headers(inner.into(), kind, headers)?,
374                cookie),
375        })))
376    }
377
378    /// Sets the version of OpenPGP to generate ASCII Armor for.
379    ///
380    /// Walks up the writer stack, looking for the next Armorer.
381    /// Configure it to use the given profile.
382    ///
383    /// This function can only be called once.  Calling it repeatedly
384    /// does nothing.
385    pub fn set_profile(stack: &mut (dyn Stackable<'a, Cookie> + Send + Sync),
386                       profile: Profile)
387    {
388        map_mut(stack, |w| match &mut w.cookie_mut().private {
389            super::Private::Armorer { set_profile, .. } => {
390                *set_profile = Some(profile);
391                Some(())
392            },
393            _ => None, // Keep looking.
394        });
395    }
396}
397
398impl<'a, C: 'a> fmt::Debug for Armorer<'a, C> {
399    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
400        f.debug_struct("writer::Armorer")
401            .field("inner", &self.inner)
402            .finish()
403    }
404}
405
406impl<'a> io::Write for Armorer<'a, Cookie> {
407    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
408        if bytes.len() == 0 {
409            return Ok(0);
410        }
411
412        // Lazily configure the armor writer.
413        if let Some(p) = match &mut self.cookie_mut().private {
414            super::Private::Armorer { set_profile } =>
415                set_profile.take(),
416            _ => None,
417        } {
418            let _ = self.inner.inner.set_profile(p);
419        }
420
421        self.inner.write(bytes)
422    }
423
424    fn flush(&mut self) -> io::Result<()> {
425        self.inner.flush()
426    }
427}
428
429impl<'a> Stackable<'a, Cookie> for Armorer<'a, Cookie> {
430    fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, Cookie>>> {
431        let inner = self.inner.inner.finalize()?;
432        Ok(Some(inner))
433    }
434    fn pop(&mut self) -> Result<Option<BoxStack<'a, Cookie>>> {
435        unreachable!("Only implemented by Signer")
436    }
437    fn mount(&mut self, _new: BoxStack<'a, Cookie>) {
438        unreachable!("Only implemented by Signer")
439    }
440    fn inner_mut(&mut self) -> Option<&mut (dyn Stackable<'a, Cookie> + Send + Sync)> {
441        Some(self.inner.inner.get_mut().as_mut())
442    }
443    fn inner_ref(&self) -> Option<&(dyn Stackable<'a, Cookie> + Send + Sync)> {
444        Some(self.inner.inner.get_ref().as_ref())
445    }
446    fn cookie_set(&mut self, cookie: Cookie) -> Cookie {
447        self.inner.cookie_set(cookie)
448    }
449    fn cookie_ref(&self) -> &Cookie {
450        self.inner.cookie_ref()
451    }
452    fn cookie_mut(&mut self) -> &mut Cookie {
453        self.inner.cookie_mut()
454    }
455    fn position(&self) -> u64 {
456        self.inner.position
457    }
458}
459
460
461/// Encrypting writer.
462pub struct Encryptor<'a, C: 'a> {
463    inner: Generic<symmetric::Encryptor<Box<dyn Stackable<'a, C> + Send + Sync + 'a>>, C>,
464}
465assert_send_and_sync!(Encryptor<'_, C> where C);
466
467impl<'a> Encryptor<'a, Cookie> {
468    /// Makes an encrypting writer.
469    pub fn new(inner: Message<'a>, cookie: Cookie, algo: SymmetricAlgorithm,
470               key: &SessionKey)
471        -> Result<Message<'a>>
472    {
473        use crate::crypto::symmetric::{
474            BlockCipherMode,
475            PaddingMode,
476        };
477
478        Ok(Message::from(Box::new(Encryptor {
479            inner: Generic::new_unboxed(
480                symmetric::Encryptor::new(
481                    algo, BlockCipherMode::CFB, PaddingMode::None,
482                    key, None, inner.into())?,
483                cookie),
484        })))
485    }
486}
487
488impl<'a, C: 'a> fmt::Debug for Encryptor<'a, C> {
489    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
490        f.debug_struct("writer::Encryptor")
491            .field("inner", &self.inner)
492            .finish()
493    }
494}
495
496impl<'a, C: 'a> io::Write for Encryptor<'a, C> {
497    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
498        self.inner.write(bytes)
499    }
500
501    fn flush(&mut self) -> io::Result<()> {
502        self.inner.flush()
503    }
504}
505
506impl<'a, C: 'a> Stackable<'a, C> for Encryptor<'a, C> {
507    fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>> {
508        let inner = self.inner.inner.finalize()?;
509        Ok(Some(inner))
510    }
511    fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>> {
512        unreachable!("Only implemented by Signer")
513    }
514    fn mount(&mut self, _new: BoxStack<'a, C>) {
515        unreachable!("Only implemented by Signer")
516    }
517    fn inner_mut(&mut self) -> Option<&mut (dyn Stackable<'a, C> + Send + Sync)> {
518        // XXX: Unfortunately, this doesn't work due to a lifetime mismatch:
519        // self.inner.inner.get_mut().map(|r| r.as_mut())
520        None
521    }
522    fn inner_ref(&self) -> Option<&(dyn Stackable<'a, C> + Send + Sync)> {
523        self.inner.inner.get_ref().map(|r| r.as_ref())
524    }
525    fn cookie_set(&mut self, cookie: C) -> C {
526        self.inner.cookie_set(cookie)
527    }
528    fn cookie_ref(&self) -> &C {
529        self.inner.cookie_ref()
530    }
531    fn cookie_mut(&mut self) -> &mut C {
532        self.inner.cookie_mut()
533    }
534    fn position(&self) -> u64 {
535        self.inner.position
536    }
537}
538
539
540/// AEAD encrypting writer.
541pub struct AEADEncryptor<'a, 's, C: 'a> {
542    inner: Generic<aead::Encryptor<'s, BoxStack<'a, C>>, C>,
543}
544assert_send_and_sync!(AEADEncryptor<'_, '_, C> where C);
545
546impl<'a, 's> AEADEncryptor<'a, 's, Cookie> {
547    /// Makes an encrypting writer.
548    pub fn new<S>(inner: Message<'a>, cookie: Cookie,
549                  cipher: SymmetricAlgorithm, aead: AEADAlgorithm,
550                  chunk_size: usize, schedule: S)
551                  -> Result<Message<'a>>
552    where
553        S: aead::Schedule<aead::EncryptionContext> + 'a + 's,
554    {
555        Ok(Message::from(Box::new(AEADEncryptor {
556            inner: Generic::new_unboxed(
557                aead::Encryptor::new(cipher, aead, chunk_size, schedule,
558                                     inner.into())?,
559                cookie),
560        })))
561    }
562}
563
564impl<'a, C: 'a> fmt::Debug for AEADEncryptor<'a, '_, C> {
565    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
566        f.debug_struct("writer::AEADEncryptor")
567            .field("inner", &self.inner)
568            .finish()
569    }
570}
571
572impl<'a, C: 'a> io::Write for AEADEncryptor<'a, '_, C> {
573    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
574        self.inner.write(bytes)
575    }
576
577    fn flush(&mut self) -> io::Result<()> {
578        self.inner.flush()
579    }
580}
581
582impl<'a, C: 'a> Stackable<'a, C> for AEADEncryptor<'a, '_, C> {
583    fn into_inner(self: Box<Self>) -> Result<Option<BoxStack<'a, C>>> {
584        let inner = self.inner.inner.finalize()?;
585        Ok(Some(inner))
586    }
587    fn pop(&mut self) -> Result<Option<BoxStack<'a, C>>> {
588        unreachable!("Only implemented by Signer")
589    }
590    fn mount(&mut self, _new: BoxStack<'a, C>) {
591        unreachable!("Only implemented by Signer")
592    }
593    fn inner_mut(&mut self) -> Option<&mut (dyn Stackable<'a, C> + Send + Sync)> {
594        // XXX: Unfortunately, this doesn't work due to a lifetime mismatch:
595        // self.inner.inner.get_mut().map(|r| r.as_mut())
596        None
597    }
598    fn inner_ref(&self) -> Option<&(dyn Stackable<'a, C> + Send + Sync)> {
599        self.inner.inner.get_ref().map(|r| r.as_ref())
600    }
601    fn cookie_set(&mut self, cookie: C) -> C {
602        self.inner.cookie_set(cookie)
603    }
604    fn cookie_ref(&self) -> &C {
605        self.inner.cookie_ref()
606    }
607    fn cookie_mut(&mut self) -> &mut C {
608        self.inner.cookie_mut()
609    }
610    fn position(&self) -> u64 {
611        self.inner.position
612    }
613}
614
615#[cfg(test)]
616mod test {
617    use std::io::Write;
618    use super::*;
619
620    #[test]
621    fn generic_writer() {
622        let mut inner = Vec::new();
623        {
624            let mut w = Generic::new(&mut inner, Cookie::new(0));
625            assert_eq!(w.as_ref().cookie_ref().level, 0);
626            dump(w.as_ref());
627
628            *w.as_mut().cookie_mut() = Cookie::new(1);
629            assert_eq!(w.as_ref().cookie_ref().level, 1);
630
631            w.write_all(b"be happy").unwrap();
632            let mut count = 0;
633            map_mut(w.as_mut(), |g| -> Option<()> {
634                let new = Cookie::new(0);
635                let old = g.cookie_set(new);
636                assert_eq!(old.level, 1);
637                count += 1;
638                None
639            });
640            assert_eq!(count, 1);
641            assert_eq!(w.as_ref().cookie_ref().level, 0);
642        }
643        assert_eq!(&inner, b"be happy");
644    }
645
646    #[test]
647    fn stack() {
648        let mut inner = Vec::new();
649        {
650            let w = Generic::new(&mut inner, Cookie::new(0));
651            dump(w.as_ref());
652
653            let w = Identity::new(w, Cookie::new(0));
654            dump(w.as_ref());
655
656            let mut count = 0;
657            map(w.as_ref(), |g| -> Option<()> {
658                assert_eq!(g.cookie_ref().level, 0);
659                count += 1;
660                None
661            });
662            assert_eq!(count, 2);
663        }
664    }
665}