cmail_rpgp/composed/message/
parser.rs1use std::iter::Peekable;
2
3use log::debug;
4
5use crate::armor::BlockType;
6use crate::composed::message::Message;
7use crate::composed::Deserializable;
8use crate::errors::{Error, Result};
9use crate::packet::Packet;
10use crate::types::{PkeskVersion, SkeskVersion, Tag};
11use crate::{Edata, Esk};
12
13pub struct MessageParser<I: Sized + Iterator<Item = Result<Packet>>> {
14 source: Peekable<I>,
15}
16
17fn next<I: Iterator<Item = Result<Packet>>>(packets: &mut Peekable<I>) -> Option<Result<Message>> {
18 while let Some(res) = packets.by_ref().next() {
19 let packet = match res {
20 Ok(packet) => packet,
21 Err(err) => return Some(Err(err)),
22 };
23
24 debug!("{:?}: ", packet);
25 let tag = packet.tag();
26 match tag {
27 Tag::LiteralData => {
28 return match packet.try_into() {
29 Ok(data) => Some(Ok(Message::Literal(data))),
30 Err(err) => Some(Err(err)),
31 };
32 }
33 Tag::CompressedData => {
34 return match packet.try_into() {
35 Ok(data) => Some(Ok(Message::Compressed(data))),
36 Err(err) => Some(Err(err)),
37 };
38 }
39 Tag::PublicKeyEncryptedSessionKey | Tag::SymKeyEncryptedSessionKey => {
42 return match packet.try_into() {
43 Ok(p) => {
44 let mut esk: Vec<Esk> = vec![p];
45
46 while let Some(res) = packets.next_if(|res| {
48 res.as_ref().is_ok_and(|p| {
49 p.tag() == Tag::PublicKeyEncryptedSessionKey
50 || p.tag() == Tag::SymKeyEncryptedSessionKey
51 })
52 }) {
53 match res {
54 Ok(packet) => esk.push(packet.try_into().expect("peeked")),
55 Err(e) => return Some(Err(e)),
56 }
57 }
58
59 let edata = match packets.next() {
61 Some(Ok(p))
62 if p.tag() == Tag::SymEncryptedData
63 || p.tag() == Tag::SymEncryptedProtectedData =>
64 {
65 Edata::try_from(p).expect("peeked")
66 }
67 Some(Ok(p)) => {
68 return Some(Err(Error::Message(format!(
69 "Expected encrypted data packet, but found {:?}",
70 p
71 ))));
72 }
73 None => {
74 return Some(Err(Error::Message(
75 "Missing encrypted data packet".to_string(),
76 )))
77 }
78 Some(Err(e)) => return Some(Err(e)),
79 };
80
81 fn esk_filter(
83 esk: Vec<Esk>,
84 pkesk_allowed: PkeskVersion,
85 skesk_allowed: SkeskVersion,
86 ) -> Vec<Esk> {
87 esk.into_iter()
88 .filter(|esk| match esk {
89 Esk::PublicKeyEncryptedSessionKey(pkesk) => {
90 pkesk.version() == pkesk_allowed
91 }
92 Esk::SymKeyEncryptedSessionKey(skesk) => {
93 skesk.version() == skesk_allowed
94 }
95 })
96 .collect()
97 }
98
99 let esk = match edata {
104 Edata::SymEncryptedData(_) => {
105 esk_filter(esk, PkeskVersion::V3, SkeskVersion::V4)
106 }
107 Edata::SymEncryptedProtectedData(ref p) if p.version() == 1 => {
108 esk_filter(esk, PkeskVersion::V3, SkeskVersion::V4)
109 }
110 Edata::SymEncryptedProtectedData(ref p) if p.version() == 2 => {
111 esk_filter(esk, PkeskVersion::V6, SkeskVersion::V6)
112 }
113 _ => {
114 return Some(Err(format_err!("Unsupported Edata variant")));
115 }
116 };
117
118 Some(Ok(Message::Encrypted { esk, edata }))
119 }
120 Err(err) => Some(Err(err)),
121 };
122 }
123 Tag::Signature => {
124 return match packet.try_into() {
125 Ok(signature) => {
126 let message = match next(packets.by_ref()) {
127 Some(Ok(m)) => Some(Box::new(m)),
128 Some(Err(err)) => return Some(Err(err)),
129 None => None,
130 };
131
132 Some(Ok(Message::Signed {
133 message,
134 one_pass_signature: None,
135 signature,
136 }))
137 }
138 Err(err) => Some(Err(err)),
139 };
140 }
141 Tag::OnePassSignature => {
142 return match packet.try_into() {
143 Ok(p) => {
144 let one_pass_signature = Some(p);
145
146 let message = match next(packets.by_ref()) {
147 Some(Ok(m)) => Some(Box::new(m)),
148 Some(Err(err)) => return Some(Err(err)),
149 None => None,
150 };
151
152 let signature = if let Some(res) = packets
153 .next_if(|res| res.as_ref().is_ok_and(|p| p.tag() == Tag::Signature))
154 {
155 match res {
156 Ok(packet) => packet.try_into().expect("peeked"),
157 Err(e) => return Some(Err(e)),
158 }
159 } else {
160 return Some(Err(format_err!(
161 "missing signature for, one pass signature"
162 )));
163 };
164
165 Some(Ok(Message::Signed {
166 message,
167 one_pass_signature,
168 signature,
169 }))
170 }
171 Err(err) => Some(Err(err)),
172 };
173 }
174 Tag::Marker => {
175 }
178 Tag::Padding => {
179 }
184 _ => {
185 return Some(Err(format_err!("unexpected packet {:?}", packet.tag())));
186 }
187 }
188 }
189
190 None
191}
192
193impl<I: Sized + Iterator<Item = Result<Packet>>> Iterator for MessageParser<I> {
194 type Item = Result<Message>;
195
196 fn next(&mut self) -> Option<Self::Item> {
197 next(self.source.by_ref())
198 }
199}
200
201impl Deserializable for Message {
202 fn from_packets<'a, I: Iterator<Item = Result<Packet>> + 'a>(
205 packets: std::iter::Peekable<I>,
206 ) -> Box<dyn Iterator<Item = Result<Self>> + 'a> {
207 Box::new(MessageParser {
208 source: packets.peekable(),
209 })
210 }
211
212 fn matches_block_type(typ: BlockType) -> bool {
213 matches!(
214 typ,
215 BlockType::Message | BlockType::MultiPartMessage(_, _) | BlockType::File
216 )
217 }
218}