1use std::fmt;
8
9#[cfg(test)]
10use quickcheck::{Arbitrary, Gen};
11
12use buffered_reader::BufferedReader;
13
14use crate::Error;
15use crate::Result;
16use crate::packet::{
17 self,
18 header::BodyLength,
19};
20use crate::Packet;
21use crate::policy::HashAlgoSecurity;
22use crate::serialize::Marshal;
23use crate::serialize::MarshalInto;
24
25#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
33pub struct UserAttribute {
34 pub(crate) common: packet::Common,
36
37 value: Vec<u8>,
39}
40assert_send_and_sync!(UserAttribute);
41
42impl From<Vec<u8>> for UserAttribute {
43 fn from(u: Vec<u8>) -> Self {
44 UserAttribute {
45 common: Default::default(),
46 value: u,
47 }
48 }
49}
50
51impl fmt::Debug for UserAttribute {
52 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
53 f.debug_struct("UserAttribute")
54 .field("value (bytes)", &self.value.len())
55 .finish()
56 }
57}
58
59impl UserAttribute {
60 pub fn new(subpackets: &[Subpacket]) -> Result<Self> {
64 let mut value = Vec::with_capacity(
65 subpackets.iter().fold(0, |l, s| l + s.serialized_len()));
66 for s in subpackets {
67 s.serialize(&mut value)?
68 }
69
70 Ok(UserAttribute {
71 common: Default::default(),
72 value
73 })
74 }
75
76 pub fn hash_algo_security(&self) -> HashAlgoSecurity {
102 HashAlgoSecurity::CollisionResistance
103 }
104
105 pub fn value(&self) -> &[u8] {
112 self.value.as_slice()
113 }
114
115 pub fn value_mut(&mut self) -> &mut Vec<u8> {
118 &mut self.value
119 }
120
121 pub fn subpackets(&self) -> SubpacketIterator {
123 SubpacketIterator {
124 reader: buffered_reader::Memory::new(&self.value[..]),
125 }
126 }
127}
128
129impl From<UserAttribute> for Packet {
130 fn from(s: UserAttribute) -> Self {
131 Packet::UserAttribute(s)
132 }
133}
134
135#[cfg(test)]
136impl Arbitrary for UserAttribute {
137 fn arbitrary(g: &mut Gen) -> Self {
138 use crate::arbitrary_helper::gen_arbitrary_from_range;
139
140 UserAttribute::new(
141 &(0..gen_arbitrary_from_range(1..10, g))
142 .map(|_| Subpacket::arbitrary(g))
143 .collect::<Vec<_>>()[..]).unwrap()
144 }
145}
146
147pub struct SubpacketIterator<'a> {
149 reader: buffered_reader::Memory<'a, ()>,
150}
151assert_send_and_sync!(SubpacketIterator<'_>);
152
153impl<'a> Iterator for SubpacketIterator<'a> {
154 type Item = Result<Subpacket>;
155 fn next(&mut self) -> Option<Self::Item> {
156 let length = match BodyLength::parse_new_format(&mut self.reader) {
157 Ok(BodyLength::Full(l)) => l,
158 Ok(BodyLength::Partial(_)) | Ok(BodyLength::Indeterminate) =>
159 return Some(Err(Error::MalformedPacket(
160 "Partial or Indeterminate length of subpacket".into())
161 .into())),
162 Err(e) =>
163 if e.kind() == ::std::io::ErrorKind::UnexpectedEof {
164 return None;
165 } else {
166 return Some(Err(e.into()));
167 },
168 };
169
170 let raw = match self.reader.data_consume_hard(length as usize) {
171 Ok(r) => &r[..length as usize],
172 Err(e) => return Some(Err(e.into())),
173 };
174
175 if raw.is_empty() {
176 return Some(Err(Error::MalformedPacket(
177 "Subpacket without type octet".into()).into()));
178 }
179
180 let typ = raw[0];
181 let raw = &raw[1..];
182 match typ {
183 1 => if raw.len() >= 16 &&
185 raw[..3] == [0x10, 0x00, 0x01]
186 && raw[4..16].iter().all(|b| *b == 0)
187 {
188 let image_kind = raw[3];
189 Some(Ok(Subpacket::Image(match image_kind {
190 1 =>
191 Image::JPEG(Vec::from(&raw[16..]).into_boxed_slice()),
192 n @ 100..=110 =>
193 Image::Private(
194 n, Vec::from(&raw[16..]).into_boxed_slice()),
195 n =>
196 Image::Unknown(
197 n, Vec::from(&raw[16..]).into_boxed_slice()),
198 })))
199 } else {
200 Some(Err(Error::MalformedPacket(
201 "Malformed image subpacket".into()).into()))
202 },
203 n =>
204 Some(Ok(Subpacket::Unknown(
205 n, Vec::from(raw).into_boxed_slice()))),
206 }
207 }
208}
209
210#[derive(Clone, Debug, PartialEq, Eq, Hash)]
216#[non_exhaustive]
217pub enum Subpacket {
218 Image(Image),
224 Unknown(u8, Box<[u8]>),
226}
227assert_send_and_sync!(Subpacket);
228
229#[cfg(test)]
230impl Arbitrary for Subpacket {
231 fn arbitrary(g: &mut Gen) -> Self {
232 use crate::arbitrary_helper::gen_arbitrary_from_range;
233
234 match gen_arbitrary_from_range(0..3, g) {
235 0 => Subpacket::Image(Image::arbitrary(g)),
236 1 => Subpacket::Unknown(
237 0,
238 Vec::<u8>::arbitrary(g).into_boxed_slice()
239 ),
240 2 => Subpacket::Unknown(
241 gen_arbitrary_from_range(2..256, g) as u8,
242 Vec::<u8>::arbitrary(g).into_boxed_slice()
243 ),
244 _ => unreachable!(),
245 }
246 }
247}
248
249#[derive(Clone, Debug, PartialEq, Eq, Hash)]
255#[non_exhaustive]
256pub enum Image {
257 JPEG(Box<[u8]>),
259 Private(u8, Box<[u8]>),
261 Unknown(u8, Box<[u8]>),
263}
264assert_send_and_sync!(Image);
265
266#[cfg(test)]
267impl Arbitrary for Image {
268
269 fn arbitrary(g: &mut Gen) -> Self {
270 use crate::arbitrary_helper::gen_arbitrary_from_range;
271
272 match gen_arbitrary_from_range(0..5, g) {
273 0 =>
274 Image::JPEG(
275 Vec::<u8>::arbitrary(g).into_boxed_slice()
276 ),
277 1 =>
278 Image::Unknown(
279 gen_arbitrary_from_range(2..100, g),
280 Vec::<u8>::arbitrary(g).into_boxed_slice()
281 ),
282 2 =>
283 Image::Private(
284 gen_arbitrary_from_range(100..111, g),
285 Vec::<u8>::arbitrary(g).into_boxed_slice()
286 ),
287 3 =>
288 Image::Unknown(
289 0,
290 Vec::<u8>::arbitrary(g).into_boxed_slice()
291 ),
292 4 =>
293 Image::Unknown(
294 gen_arbitrary_from_range(111..256, g) as u8,
295 Vec::<u8>::arbitrary(g).into_boxed_slice()
296 ),
297 _ => unreachable!(),
298 }
299 }
300}
301
302
303#[cfg(test)]
304mod tests {
305 use super::*;
306 use crate::parse::Parse;
307
308 quickcheck! {
309 fn roundtrip(p: UserAttribute) -> bool {
310 let buf = p.to_vec().unwrap();
311 assert_eq!(p.serialized_len(), buf.len());
312 let q = UserAttribute::from_bytes(&buf).unwrap();
313 assert_eq!(p, q);
314 true
315 }
316 }
317
318 quickcheck! {
319 fn roundtrip_subpacket(sp: Subpacket) -> bool {
320 let value = sp.to_vec().unwrap();
321 assert_eq!(sp.serialized_len(), value.len());
322 let ua = UserAttribute {
323 common: Default::default(),
324 value,
325 };
326 let buf = ua.to_vec().unwrap();
327 let q = UserAttribute::from_bytes(&buf).unwrap();
328 let subpackets = q.subpackets().collect::<Vec<_>>();
329 assert_eq!(subpackets.len(), 1);
330 assert_eq!(&sp, subpackets[0].as_ref().unwrap());
331 true
332 }
333 }
334
335 quickcheck! {
336 fn roundtrip_image(img: Image) -> bool {
337 let mut body = img.to_vec().unwrap();
338 assert_eq!(img.serialized_len(), body.len());
339 let mut value =
340 BodyLength::Full(1 + body.len() as u32).to_vec().unwrap();
341 value.push(1); value.append(&mut body);
343 let ua = UserAttribute {
344 common: Default::default(),
345 value,
346 };
347 let buf = ua.to_vec().unwrap();
348 let q = UserAttribute::from_bytes(&buf).unwrap();
349 let subpackets = q.subpackets().collect::<Vec<_>>();
350 assert_eq!(subpackets.len(), 1);
351 if let Ok(Subpacket::Image(i)) = &subpackets[0] {
352 assert_eq!(&img, i);
353 } else {
354 panic!("expected image subpacket, got {:?}", subpackets[0]);
355 }
356 true
357 }
358 }
359
360 #[test]
361 fn image() {
362 use crate::Packet;
363 let p = Packet::from_bytes("
364-----BEGIN PGP ARMORED FILE-----
365
3660cFuwWwBEAABAQAAAAAAAAAAAAAAAP/Y/+AAEEpGSUYAAQEBASwBLAAA//4AE0Ny
367ZWF0ZWQgd2l0aCBHSU1Q/9sAQwADAgIDAgIDAwMDBAMDBAUIBQUEBAUKBwcGCAwK
368DAwLCgsLDQ4SEA0OEQ4LCxAWEBETFBUVFQwPFxgWFBgSFBUU/9sAQwEDBAQFBAUJ
369BQUJFA0LDRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU
370FBQUFBQUFBQU/8IAEQgAAQABAwERAAIRAQMRAf/EABQAAQAAAAAAAAAAAAAAAAAA
371AAj/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAFUn//EABQQAQAA
372AAAAAAAAAAAAAAAAAAD/2gAIAQEAAQUCf//EABQRAQAAAAAAAAAAAAAAAAAAAAD/
3732gAIAQMBAT8Bf//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Bf//EABQQ
374AQAAAAAAAAAAAAAAAAAAAAD/2gAIAQEABj8Cf//EABQQAQAAAAAAAAAAAAAAAAAA
375AAD/2gAIAQEAAT8hf//aAAwDAQACAAMAAAAQn//EABQRAQAAAAAAAAAAAAAAAAAA
376AAD/2gAIAQMBAT8Qf//EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQIBAT8Qf//E
377ABQQAQAAAAAAAAAAAAAAAAAAAAD/2gAIAQEAAT8Qf//Z
378=nUQg
379-----END PGP ARMORED FILE-----
380").unwrap();
381 let subpackets: Vec<_> = if let Packet::UserAttribute(ua) = p {
382 ua.subpackets().collect()
383 } else {
384 panic!("Expected a UserAttribute, got: {:?}", p);
385 };
386 assert_eq!(subpackets.len(), 1);
387 if let Ok(Subpacket::Image(Image::JPEG(img))) = &subpackets[0] {
388 assert_eq!(img.len(), 539 );
389 assert_eq!(&img[6..10], b"JFIF");
390 assert_eq!(&img[24..41], b"Created with GIMP");
391 } else {
392 panic!("Expected JPEG, got {:?}", &subpackets[0]);
393 }
394
395 if let Ok(Subpacket::Image(img)) = &subpackets[0] {
396 let buf = img.to_vec().unwrap();
397 assert_eq!(buf.len(), 539 + 16 );
398 assert_eq!(img.serialized_len(), 539 + 16 );
399 } else {
400 unreachable!("decomposed fine before");
401 }
402
403 if let Ok(img) = &subpackets[0] {
404 let buf = img.to_vec().unwrap();
405 assert_eq!(buf.len(), 539 + 16 + 3 );
406 assert_eq!(img.serialized_len(), 539 + 16 + 3 );
407 } else {
408 unreachable!("decomposed fine before");
409 }
410 }
411}