1#![doc(html_favicon_url = "https://docs.sequoia-pgp.org/favicon.png")]
13#![doc(html_logo_url = "https://docs.sequoia-pgp.org/logo.svg")]
14#![warn(missing_docs)]
15
16use std::convert::TryFrom;
17use std::io;
18use std::io::prelude::*;
19use std::io::BufReader;
20use std::path::Path;
21use std::fmt::Debug;
22use std::fs::File;
23use std::str;
24
25use base64::Engine;
26use base64::engine::general_purpose::STANDARD as base64std;
27
28use sequoia_openpgp as openpgp;
29use openpgp::armor;
30use openpgp::Error;
31pub use openpgp::Result;
32use openpgp::Packet;
33use openpgp::packet::SKESK;
34use openpgp::cert::prelude::*;
35use openpgp::parse::{
36 Parse,
37 PacketParserResult, PacketParser,
38 buffered_reader::BufferedReader,
39};
40use openpgp::serialize::Serialize;
41use openpgp::serialize::stream::{
42 Message, LiteralWriter, Encryptor,
43};
44use openpgp::crypto::Password;
45use openpgp::policy::Policy;
46use openpgp::types::RevocationStatus;
47
48mod cert;
49pub use cert::cert_builder;
50
51pub enum Autocrypt {
54 V1,
56 V1_1,
58}
59
60impl Default for Autocrypt {
61 fn default() -> Self { Autocrypt::V1_1 }
62}
63
64#[derive(Debug, PartialEq)]
66pub struct Attribute {
67 pub critical: bool,
69 pub key: String,
74 pub value: String,
76}
77
78#[derive(Debug, PartialEq)]
81pub enum AutocryptHeaderType {
82 Sender,
84 Gossip,
86}
87
88#[derive(Debug, PartialEq)]
90pub struct AutocryptHeader {
91 pub header_type: AutocryptHeaderType,
93
94 pub key: Option<Cert>,
96
97 pub attributes: Vec<Attribute>,
99}
100
101impl AutocryptHeader {
102 fn empty(header_type: AutocryptHeaderType) -> Self {
103 AutocryptHeader {
104 header_type,
105 key: None,
106 attributes: Vec::new(),
107 }
108 }
109
110 pub fn new_sender<'a, P>(policy: &dyn Policy,
112 cert: &Cert, addr: &str, prefer_encrypt: P)
113 -> Result<Self>
114 where P: Into<Option<&'a str>>
115 {
116 let mut acc = Vec::new();
118
119 let primary = cert.primary_key().with_policy(policy, None)?;
121 acc.push(primary.key().clone().into());
122 primary.self_signatures().take(1)
123 .for_each(|s| acc.push(s.clone().into()));
124
125 for skb in cert.keys().with_policy(policy, None).subkeys() {
127 if let RevocationStatus::Revoked(_) = skb.revocation_status() {
129 continue;
130 }
131 if skb.for_signing() || skb.for_transport_encryption() {
132 let k = skb.key().clone();
133 acc.push(k.into());
134 acc.push(skb.binding_signature().clone().into());
135 }
136 }
137
138 let mut found_one = false;
140 for uidb in cert.userids().with_policy(policy, None) {
141 if let Ok(Some(a)) = uidb.userid().email() {
143 if a == addr {
144 acc.push(uidb.userid().clone().into());
145 acc.push(uidb.binding_signature().clone().into());
146 found_one = true;
147 } else {
148 continue;
150 }
151 } else {
152 continue;
154 }
155 }
156
157 if ! found_one {
161 if let Ok(uidb) = cert.with_policy(policy, None)?.primary_userid() {
162 acc.push(uidb.userid().clone().into());
163 acc.push(uidb.binding_signature().clone().into());
164 }
165 }
166
167 let cleaned_cert = Cert::try_from(acc)?;
168
169 Ok(AutocryptHeader {
170 header_type: AutocryptHeaderType::Sender,
171 key: Some(cleaned_cert),
172 attributes: vec![
173 Attribute {
174 critical: true,
175 key: "addr".into(),
176 value: addr.into(),
177 },
178 Attribute {
179 critical: true,
180 key: "prefer-encrypt".into(),
181 value: prefer_encrypt.into()
182 .unwrap_or("nopreference").into(),
183 },
184 ],
185 })
186 }
187
188 pub fn get(&self, key: &str) -> Option<&Attribute> {
190 for a in &self.attributes {
191 if a.key == key {
192 return Some(a);
193 }
194 }
195
196 None
197 }
198
199 pub fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> {
201 if self.key.is_none() {
202 return Err(Error::InvalidOperation("No key".into()).into());
203 }
204
205 for attr in self.attributes.iter() {
206 write!(o, "{}={}; ", attr.key, attr.value)?;
207 }
208
209 let mut buf = Vec::new();
210 self.key.as_ref().unwrap().serialize(&mut buf)?;
211 write!(o, "keydata={} ", base64std.encode(&buf))?;
212 Ok(())
213 }
214
215}
216
217#[derive(Debug, PartialEq)]
219pub struct AutocryptHeaders {
220 pub from: Option<String>,
222
223 pub headers: Vec<AutocryptHeader>,
225}
226
227impl AutocryptHeaders {
228 fn empty() -> Self {
229 AutocryptHeaders {
230 from: None,
231 headers: Vec::new(),
232 }
233 }
234
235 fn from_lines<I: Iterator<Item = io::Result<String>>>(mut lines: I)
236 -> Result<Self>
237 {
238 let mut headers = AutocryptHeaders::empty();
239
240 let mut next_line = lines.next();
241 while let Some(line) = next_line {
242 let mut line = line?;
244
245 if line.is_empty() {
246 break;
248 }
249
250 next_line = lines.next();
251
252 while let Some(Ok(nl)) = next_line {
258 if !nl.is_empty() && (nl.starts_with(|c| c == ' ' || c == '\t'))
259 {
260 line.push_str(&nl);
261 next_line = lines.next();
262 } else {
263 next_line = Some(Ok(nl));
265 break;
266 }
267 }
268
269 const AUTOCRYPT : &str = "Autocrypt: ";
270 const AUTOCRYPT_GOSSIP : &str = "Autocrypt-Gossip: ";
271 const FROM : &str = "From: ";
272
273 if let Some(rest) = line.strip_prefix(FROM) {
274 headers.from = Some(rest.trim_matches(' ').into());
275 } else {
276 if let Some((key, value)) =
277 if let Some(v) = line.strip_prefix(AUTOCRYPT) {
278 Some((AutocryptHeaderType::Sender, v))
279 } else if let Some(v) = line.strip_prefix(AUTOCRYPT_GOSSIP) {
280 Some((AutocryptHeaderType::Gossip, v))
281 } else {
282 None
283 }
284 {
285 headers.headers.push(
286 Self::decode_autocrypt_like_header(key, value));
287 }
288 }
289 }
290
291 Ok(headers)
292 }
293
294 fn decode_autocrypt_like_header(header_type: AutocryptHeaderType,
298 ac_value: &str)
299 -> AutocryptHeader
300 {
301 let mut header = AutocryptHeader::empty(header_type);
302
303 for pair in ac_value.split(';') {
304 let pair = pair
305 .splitn(2, '=')
306 .collect::<Vec<&str>>();
307
308 let (key, value) : (&str, String) = if pair.len() == 1 {
309 (pair[0].trim_matches(' '), "".into())
311 } else {
312 (pair[0].trim_matches(' '),
313 pair[1].trim_matches(' ').into())
314 };
315
316 if key == "keydata" {
317 if let Ok(decoded) = base64std.decode(
318 &value.replace(' ', "")[..]) {
319 if let Ok(cert) = Cert::from_bytes(&decoded[..]) {
320 header.key = Some(cert);
321 }
322 }
323 }
324
325 let (critical, key) = if let Some(key) = key.strip_prefix('_') {
326 (true, key)
327 } else {
328 (false, key)
329 };
330 header.attributes.push(Attribute {
331 critical,
332 key: key.to_string(),
333 value,
334 });
335 }
336 header
337 }
338
339 pub fn from_bytes(data: &[u8]) -> Result<Self> {
343 let lines = BufReader::new(io::Cursor::new(data)).lines();
344 Self::from_lines(lines)
345 }
346
347 pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
353 Self::from_reader(File::open(path)?)
354 }
355
356 pub fn from_reader<R: io::Read>(reader: R) -> Result<Self> {
361 Self::from_lines(BufReader::new(reader).lines())
362 }
363
364 pub fn from_buffered_reader<R, C>(mut reader: R) -> Result<Self>
368 where R: BufferedReader<C>,
369 C: Debug + Send + Sync
370 {
371 Self::from_bytes(reader.data_eof()?)
372 }
373}
374
375#[derive(Debug, PartialEq)]
383pub struct AutocryptSetupMessage {
384 prefer_encrypt: Option<String>,
385 passcode_format: Option<String>,
386 passcode: Option<Password>,
387 passcode_begin: Option<String>,
391
392 cert: Cert,
393}
394
395impl AutocryptSetupMessage {
396 pub fn new(cert: Cert) -> Self {
407 AutocryptSetupMessage {
408 prefer_encrypt: None,
409 passcode: None,
410 passcode_format: None,
411 passcode_begin: None,
412 cert,
413 }
414 }
415
416 pub fn set_prefer_encrypt(mut self, value: &str) -> Self {
418 self.prefer_encrypt = Some(value.into());
419 self
420 }
421
422 pub fn prefer_encrypt(&self) -> Option<&str> {
424 self.prefer_encrypt.as_ref().map(|v| &v[..])
425 }
426
427
428 pub fn set_passcode_format(mut self, value: &str) -> Self {
430 self.passcode_format = Some(value.into());
431 self
432 }
433
434 pub fn passcode_format(&self) -> Option<&str> {
436 self.passcode_format.as_ref().map(|v| &v[..])
437 }
438
439
440 pub fn set_passcode(mut self, passcode: Password) -> Self {
442 self.passcode = Some(passcode);
443 self
444 }
445
446 pub fn passcode(&self) -> Option<&Password> {
451 self.passcode.as_ref()
452 }
453
454
455 pub fn set_passcode_begin(mut self, value: &str) -> Self {
457 self.passcode_begin = Some(value.into());
458 self
459 }
460
461 pub fn passcode_begin(&self) -> Option<&str> {
463 self.passcode_begin.as_ref().map(|v| &v[..])
464 }
465
466
467 fn passcode_gen() -> Result<Password> {
469 use openpgp::crypto::mem;
470 let mut p_as_vec = mem::Protected::from(vec![0; 15]);
476 openpgp::crypto::random(&mut p_as_vec[..])?;
477
478 let mut p_as_u128 = 0u128;
480 for v in p_as_vec.iter() {
481 p_as_u128 = (p_as_u128 << 8) + *v as u128;
482 }
483
484 let mut p : Vec<u8> = Vec::new();
486 for i in 0..36 {
487 if i > 0 && i % 4 == 0 {
488 p.push(b'-');
489 }
490
491 p.push(b'0' + ((p_as_u128 as u8) % 10));
492 p_as_u128 /= 10;
493 }
494
495 Ok(p.into())
496 }
497
498 fn passcode_ensure(&mut self) -> Result<()> {
500 if self.passcode.is_some() {
501 return Ok(());
502 }
503
504 let passcode = Self::passcode_gen()?;
505 self.passcode_format = Some("numeric9x4".into());
506 self.passcode_begin = passcode.map(|p| {
507 Some(str::from_utf8(&p[..2]).unwrap().into())
508 });
509 self.passcode = Some(passcode);
510 Ok(())
511 }
512
513 pub fn serialize<W>(&mut self, w: &mut W) -> Result<()>
517 where W: io::Write + Send + Sync,
518 {
519 self.passcode_ensure()?;
525
526 let mut headers : Vec<(&str, &str)> = Vec::new();
527 if let Some(ref format) = self.passcode_format {
528 headers.push(
529 ("Passphrase-Format", &format[..]));
530 }
531 if let Some(ref begin) = self.passcode_begin {
532 headers.push(
533 ("Passphrase-Begin", &begin[..]));
534 }
535
536 let mut armor_writer =
537 armor::Writer::with_headers(w, armor::Kind::Message, headers)?;
538
539 {
540 let m = Message::new(&mut armor_writer);
542 let m = Encryptor::with_passwords(
543 m, vec![self.passcode.clone().unwrap()]).build()?;
544
545 let m = LiteralWriter::new(m).build()?;
546
547 let mut w = armor::Writer::with_headers(
549 m, armor::Kind::SecretKey,
550 vec![("Autocrypt-Prefer-Encrypt",
551 self.prefer_encrypt().unwrap_or("nopreference"))])?;
552
553 self.cert.as_tsk().serialize(&mut w)?;
554 let m = w.finalize()?;
555 m.finalize()?;
556 }
557 armor_writer.finalize()?;
558 Ok(())
559 }
560
561
562 pub fn from_bytes(bytes: &[u8])
566 -> Result<AutocryptSetupMessageParser>
567 {
568 Self::from_reader(bytes)
569 }
570
571 pub fn from_reader<'a, R: io::Read + Send + Sync + 'a>(r: R)
575 -> Result<AutocryptSetupMessageParser<'a>> {
576 let mut r = armor::Reader::from_reader(
579 r, armor::ReaderMode::Tolerant(Some(armor::Kind::Message)));
580
581 let (format, begin) = {
585 let headers = r.headers()?;
586
587 let format = headers.iter()
588 .filter_map(|(k, v)| {
589 if k == "Passphrase-Format" { Some(v) } else { None }
590 })
591 .collect::<Vec<&String>>();
592 let format = if !format.is_empty() {
593 Some(format[0].clone())
596 } else {
597 None
598 };
599
600 let begin = headers.iter()
601 .filter_map(|(k, v)| {
602 if k == "Passphrase-Begin" { Some(v) } else { None }
603 })
604 .collect::<Vec<&String>>();
605 let begin = if !begin.is_empty() {
606 Some(begin[0].clone())
609 } else {
610 None
611 };
612
613 (format, begin)
614 };
615
616 let mut ppr = PacketParser::from_reader(r)?;
619
620 let pp = if let PacketParserResult::Some(pp) = ppr {
625 pp
626 } else {
627 return Err(
628 Error::MalformedMessage(
629 "Premature EOF: expected an SK-ESK, encountered EOF".into())
630 .into());
631 };
632
633 let (packet, ppr_) = pp.next()?;
634 ppr = ppr_;
635
636 let skesk = match packet {
637 Packet::SKESK(skesk) => skesk,
638 p => return Err(
639 Error::MalformedMessage(
640 format!("Expected a SKESK packet, found a {}", p.tag()))
641 .into()),
642 };
643
644 let pp = match ppr {
645 PacketParserResult::EOF(_) =>
646 return Err(
647 Error::MalformedMessage(
648 "Pre-mature EOF after reading SK-ESK packet".into())
649 .into()),
650 PacketParserResult::Some(pp) => {
651 match pp.packet {
652 Packet::SEIP(_) => (),
653 ref p => return Err(
654 Error::MalformedMessage(
655 format!("Expected a SEIP packet, found a {}",
656 p.tag()))
657 .into()),
658 }
659
660 pp
661 }
662 };
663
664 Ok(AutocryptSetupMessageParser {
665 passcode_format: format,
666 passcode_begin: begin,
667 skesk,
668 pp,
669 passcode: None,
670 })
671 }
672
673 pub fn into_cert(self) -> Cert {
676 self.cert
677 }
678}
679
680pub struct AutocryptSetupMessageParser<'a> {
682 passcode_format: Option<String>,
683 passcode_begin: Option<String>,
684 skesk: SKESK,
685 pp: PacketParser<'a>,
686 passcode: Option<Password>,
687}
688
689impl<'a> AutocryptSetupMessageParser<'a> {
690 pub fn passcode_format(&self) -> Option<&str> {
692 self.passcode_format.as_ref().map(|v| &v[..])
693 }
694
695 pub fn passcode_begin(&self) -> Option<&str> {
697 self.passcode_begin.as_ref().map(|v| &v[..])
698 }
699
700 pub fn decrypt(&mut self, passcode: &Password) -> Result<()> {
706 if self.pp.processed() {
707 return Err(
708 Error::InvalidOperation("Already decrypted".into()).into());
709 }
710
711 let (algo, key) = self.skesk.decrypt(passcode)?;
712 self.pp.decrypt(algo, &key)?;
713
714 self.passcode = Some(passcode.clone());
715
716 Ok(())
717 }
718
719 pub fn parse(self) -> Result<AutocryptSetupMessage> {
730 if ! self.pp.processed() {
731 return Err(
732 Error::InvalidOperation("Not decrypted".into()).into());
733 }
734
735 let mut ppr = self.pp.recurse()?.1;
737 if ppr.as_ref().map(|pp| pp.recursion_depth()).ok() != Some(1) {
738 return Err(
739 Error::MalformedMessage(
740 "SEIP container empty, but expected a Literal Data packet"
741 .into())
742 .into());
743 }
744
745 let (prefer_encrypt, cert) = if let PacketParserResult::Some(mut pp) = ppr {
747 match pp.packet {
748 Packet::Literal(_) => (),
749 p => return Err(Error::MalformedMessage(
750 format!("SEIP container contains a {}, \
751 expected a Literal Data packet",
752 p.tag())).into()),
753 }
754
755 let (prefer_encrypt, cert) = {
758 let mut r = armor::Reader::from_reader(
759 &mut pp,
760 armor::ReaderMode::Tolerant(
761 Some(armor::Kind::SecretKey)));
762
763 let prefer_encrypt = {
764 let headers = r.headers()?;
765 let prefer_encrypt = headers.iter()
766 .filter_map(|(k, v)| {
767 if k == "Autocrypt-Prefer-Encrypt" {
768 Some(v)
769 } else {
770 None
771 }
772 })
773 .collect::<Vec<&String>>();
774
775 if !prefer_encrypt.is_empty() {
776 Some(prefer_encrypt[0].clone())
779 } else {
780 None
781 }
782 };
783
784 let cert = Cert::from_reader(r)?;
785
786 (prefer_encrypt, cert)
787 };
788
789 ppr = pp.recurse()?.1;
790
791 (prefer_encrypt, cert)
792 } else {
793 return Err(
794 Error::MalformedMessage(
795 "Pre-mature EOF after reading SEIP packet".into())
796 .into());
797 };
798
799 if let PacketParserResult::Some(pp) = ppr {
801 match pp.packet {
802 #[allow(deprecated)]
803 Packet::MDC(_) => (),
804 ref p => return
805 Err(Error::MalformedMessage(
806 format!("Expected an MDC packet, got a {}",
807 p.tag()))
808 .into()),
809 }
810
811 ppr = pp.recurse()?.1;
812 }
813
814 match ppr {
816 PacketParserResult::EOF(pp) => {
817 if let Err(err) = pp.is_message() {
821 return Err(err.context("Invalid OpenPGP Message"));
822 }
823 }
824 PacketParserResult::Some(pp) =>
825 return Err(Error::MalformedMessage(
826 format!("Extraneous packet: {}.", pp.packet.tag()))
827 .into()),
828 }
829
830 Ok(AutocryptSetupMessage {
832 prefer_encrypt,
833 passcode: self.passcode,
834 passcode_format: self.passcode_format,
835 passcode_begin: self.passcode_begin,
836 cert,
837 })
838 }
839}
840
841#[cfg(test)]
842mod test {
843 use sequoia_openpgp::parse::buffered_reader;
844 use super::*;
845
846 use openpgp::policy::StandardPolicy as P;
847
848 #[test]
849 fn decode_test() {
850 let ac = AutocryptHeaders::from_bytes(
851 &include_bytes!("../tests/data/hpk.txt")[..]
852 )
853 .unwrap();
854 assert_eq!(ac.headers.len(), 1);
858
859 assert_eq!(ac.headers[0].header_type, AutocryptHeaderType::Sender);
860 assert_eq!(ac.headers[0].get("addr").unwrap().value,
861 "holger@merlinux.eu");
862
863 assert_eq!(ac.headers[0].get("prefer-encrypt").unwrap().value,
864 "mutual");
865
866 let cert = ac.headers[0].key.as_ref()
867 .expect("Failed to parse key material.");
868 assert_eq!(cert.fingerprint(),
869 "156962B0F3115069ACA970C68E3B03A279B772D6".parse().unwrap());
870 assert_eq!(cert.userids().next().unwrap().userid().value(),
871 &b"holger krekel <holger@merlinux.eu>"[..]);
872
873
874 let ac = AutocryptHeaders::from_bytes(
875 &include_bytes!("../tests/data/vincent.txt")[..]
876 )
877 .unwrap();
878 assert_eq!(ac.from,
881 Some("Vincent Breitmoser <look@my.amazin.horse>".into()));
882
883 assert_eq!(ac.headers.len(), 1);
885
886 assert_eq!(ac.headers[0].get("addr").unwrap().value,
887 "look@my.amazin.horse");
888
889 assert!(ac.headers[0].get("prefer_encrypt").is_none());
890
891 let cert = ac.headers[0].key.as_ref()
892 .expect("Failed to parse key material.");
893 assert_eq!(cert.fingerprint(),
894 "D4AB192964F76A7F8F8A9B357BD18320DEADFA11".parse().unwrap());
895 assert_eq!(cert.userids().next().unwrap().userid().value(),
896 &b"Vincent Breitmoser <look@my.amazin.horse>"[..]);
897
898
899 let ac = AutocryptHeaders::from_bytes(
900 &include_bytes!("../tests/data/patrick.txt")[..]
901 )
902 .unwrap();
903 assert_eq!(ac.from,
906 Some("Patrick Brunschwig <patrick@enigmail.net>".into()));
907
908 assert_eq!(ac.headers.len(), 1);
910
911 assert_eq!(ac.headers[0].get("addr").unwrap().value,
912 "patrick@enigmail.net");
913
914 assert!(ac.headers[0].get("prefer_encrypt").is_none());
915
916 let cert = ac.headers[0].key.as_ref()
917 .expect("Failed to parse key material.");
918 assert_eq!(cert.fingerprint(),
919 "4F9F89F5505AC1D1A260631CDB1187B9DD5F693B".parse().unwrap());
920 assert_eq!(cert.userids().next().unwrap().userid().value(),
921 &b"Patrick Brunschwig <patrick@enigmail.net>"[..]);
922
923 let ac2 = AutocryptHeaders::from_bytes(
924 &include_bytes!("../tests/data/patrick_unfolded.txt")[..]
925 )
926 .unwrap();
927 assert_eq!(ac, ac2);
928 }
929
930 #[test]
931 fn parse_from_buffered_reader() {
932 let ac1_bytes = AutocryptHeaders::from_bytes(
935 &include_bytes!("../tests/data/hpk.txt")[..]
936 )
937 .unwrap();
938 let ac2_bytes = AutocryptHeaders::from_bytes(
939 &include_bytes!("../tests/data/vincent.txt")[..]
940 )
941 .unwrap();
942 let ac3_bytes = AutocryptHeaders::from_bytes(
943 &include_bytes!("../tests/data/patrick_unfolded.txt")[..]
944 )
945 .unwrap();
946
947 let ac1_br = AutocryptHeaders::from_buffered_reader(
948 buffered_reader::File::open("tests/data/hpk.txt").unwrap()
949 )
950 .unwrap();
951 let ac2_br = AutocryptHeaders::from_buffered_reader(
952 buffered_reader::File::open("tests/data/vincent.txt").unwrap()
953 )
954 .unwrap();
955 let ac3_br = AutocryptHeaders::from_buffered_reader(
956 buffered_reader::File::open("tests/data/patrick_unfolded.txt").unwrap()
957 )
958 .unwrap();
959
960 assert_eq!(ac1_bytes, ac1_br);
961 assert_eq!(ac2_bytes, ac2_br);
962 assert_eq!(ac3_bytes, ac3_br);
963 }
964
965 #[test]
966 fn decode_gossip() {
967 let ac = AutocryptHeaders::from_bytes(
968 &include_bytes!("../tests/data/gossip.txt")[..]
969 )
970 .unwrap();
971 assert_eq!(ac.headers.len(), 2);
975
976 assert_eq!(ac.headers[0].header_type, AutocryptHeaderType::Gossip);
977 assert_eq!(ac.headers[0].get("addr").unwrap().value,
978 "dkg@fifthhorseman.net");
979
980 assert_eq!(ac.headers[1].get("addr").unwrap().value,
981 "neal@walfield.org");
982
983 let cert = ac.headers[0].key.as_ref()
984 .expect("Failed to parse key material.");
985 assert_eq!(cert.fingerprint(),
986 "C4BC2DDB38CCE96485EBE9C2F20691179038E5C6".parse().unwrap());
987 assert_eq!(cert.userids().next().unwrap().userid().value(),
988 &b"Daniel Kahn Gillmor <dkg@fifthhorseman.net>"[..]);
989
990 }
991
992 #[test]
993 fn passcode_gen_test() {
994 let mut dist = [0usize; 10];
995
996 let samples = 8 * 1024;
997
998 let digits = 36;
1001 let passcode_len = 36 + (36 / 4 - 1);
1002
1003 for _ in 0..samples {
1004 let p = AutocryptSetupMessage::passcode_gen().unwrap();
1005 p.map(|p| {
1006 assert_eq!(p.len(), passcode_len);
1007
1008 for c in p.iter() {
1009 match *c as char {
1010 '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' => {
1011 let i = *c as usize - ('0' as usize);
1012 dist[i] = dist[i] + 1
1013 },
1014 '-' => (),
1015 _ => panic!("Unexpected character in passcode: {}", c),
1016 }
1017 }
1018 });
1019 }
1020
1021 let expected_value = (samples * digits) as f32 / 10.;
1027 let lower = (expected_value * 0.9) as usize;
1030 let upper = (expected_value * 1.1) as usize;
1031 let expected_value = expected_value as usize;
1032
1033 eprintln!("Distribution (expected value: {}, bounds: {}..{}):",
1034 expected_value, lower, upper);
1035 let mut bad = 0;
1036 for (i, count) in dist.iter()
1037 .map(|x| *x)
1038 .enumerate()
1039 .collect::<Vec<(usize, usize)>>()
1040 {
1041 let is_good = lower < count && count < upper;
1042 eprintln!("{}: {} occurrences{}.",
1043 i, count, if is_good { "" } else { " UNLIKELY" });
1044
1045 if !is_good {
1046 bad = bad + 1;
1047 }
1048 }
1049
1050 assert!(bad <= 1);
1056 }
1057
1058 #[test]
1059 fn autocrypt_setup_message() {
1060 let mut asm = AutocryptSetupMessage::from_bytes(
1062 &include_bytes!("../tests/data/setup-message.txt")[..]).unwrap();
1063
1064 assert!(asm.decrypt(&"123".into()).is_err());
1066 assert!(asm.decrypt(
1068 &"1742-0185-6197-1303-7016-8412-3581-4441-0597".into()
1069 ).is_ok());
1070 let asm = asm.parse().unwrap();
1071
1072 assert_eq!(asm.into_cert().fingerprint(),
1074 "E604 68CE 44D7 7C3F CE9F D072 71DB C565 7FDE 65A7".parse()
1075 .unwrap());
1076
1077
1078 let cert =
1081 Cert::from_bytes(&include_bytes!("../tests/data/testy-private.pgp")[..])
1082 .unwrap();
1083
1084 let mut asm = AutocryptSetupMessage::new(cert)
1085 .set_prefer_encrypt("mutual");
1086 let mut buffer = Vec::new();
1087 asm.serialize(&mut buffer).unwrap();
1088
1089 let mut asm2 = AutocryptSetupMessage::from_bytes(&buffer[..]).unwrap();
1090 asm2.decrypt(asm.passcode().unwrap()).unwrap();
1091 let asm2 = asm2.parse().unwrap();
1092 assert_eq!(asm, asm2);
1093 }
1094
1095 #[test]
1096 fn autocrypt_header_new() {
1097 let p = &P::new();
1098
1099 let cert = Cert::from_bytes(&include_bytes!("../tests/data/testy.pgp")[..])
1100 .unwrap();
1101 let header = AutocryptHeader::new_sender(p, &cert, "testy@example.org",
1102 "mutual").unwrap();
1103 let mut buf = Vec::new();
1104 write!(&mut buf, "Autocrypt: ").unwrap();
1105 header.serialize(&mut buf).unwrap();
1106
1107 let ac = AutocryptHeaders::from_bytes(&buf).unwrap();
1108
1109 assert_eq!(ac.headers.len(), 1);
1111
1112 assert_eq!(ac.headers[0].get("addr").unwrap().value,
1113 "testy@example.org");
1114
1115 assert_eq!(ac.headers[0].get("prefer-encrypt").unwrap().value,
1116 "mutual");
1117
1118 let cert = ac.headers[0].key.as_ref()
1119 .expect("Failed to parse key material.");
1120 assert_eq!(&cert.fingerprint().to_hex(),
1121 "3E8877C877274692975189F5D03F6F865226FE8B");
1122 assert_eq!(cert.userids().len(), 1);
1123 assert_eq!(cert.keys().subkeys().count(), 1);
1124 assert_eq!(cert.userids().next().unwrap().userid().value(),
1125 &b"Testy McTestface <testy@example.org>"[..]);
1126 }
1127
1128 #[test]
1129 fn autocrypt_header_new_address_mismatch() -> Result<()> {
1130 let p = &P::new();
1131
1132 let cert =
1133 Cert::from_bytes(&include_bytes!("../tests/data/testy.pgp")[..])?;
1134 let header = AutocryptHeader::new_sender(p, &cert,
1135 "anna-lena@example.org",
1136 "mutual")?;
1137 let mut buf = Vec::new();
1138 write!(&mut buf, "Autocrypt: ")?;
1139 header.serialize(&mut buf)?;
1140
1141 let ac = AutocryptHeaders::from_bytes(&buf)?;
1142
1143 assert_eq!(ac.headers.len(), 1);
1145
1146 assert_eq!(ac.headers[0].get("addr").unwrap().value,
1147 "anna-lena@example.org");
1148
1149 assert_eq!(ac.headers[0].get("prefer-encrypt").unwrap().value,
1150 "mutual");
1151
1152 let cert = ac.headers[0].key.as_ref()
1153 .expect("Failed to parse key material.");
1154 assert_eq!(&cert.fingerprint().to_hex(),
1155 "3E8877C877274692975189F5D03F6F865226FE8B");
1156 assert_eq!(cert.userids().len(), 1);
1157 assert_eq!(cert.keys().subkeys().count(), 1);
1158 assert_eq!(cert.userids().next().unwrap().userid().value(),
1159 &b"Testy McTestface <testy@example.org>"[..]);
1160 Ok(())
1161 }
1162
1163 #[test]
1165 fn issue_743() {
1166 let data: Vec<u8> = vec![
1167 0x41, 0x75, 0x02, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20,
1168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x0a, 0xc4,
1169 0x83, 0x40, 0x39, 0x0a, 0x38, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
1170 0x20, 0x74, 0x6f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x3a, 0x00, 0x00,
1171 0x0a, 0x0a, 0x0a, 0x0a, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1172 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
1173 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
1174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1175 0x00, 0x01, 0x35, 0x39, 0x33, 0x35, 0x38, 0x36, 0x34, 0x00, 0x00,
1176 0x01, 0x00, 0x00, 0x00, 0x3e, 0x3f, 0x00, 0x08, 0x00, 0x00, 0x00,
1177 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x3e, 0x08,
1178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x01, 0x08, 0x00,
1179 0x00, 0x41, 0x75, 0x74, 0x6f, 0x63, 0x72, 0x79, 0x20, 0x02, 0x01,
1180 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1181 0x00, 0x00, 0x00, 0x00, 0x01, 0x70,
1182 ];
1183 let _ = AutocryptHeaders::from_bytes(&data);
1184 }
1185
1186 #[test]
1187 fn issue_1012() {
1188 let data: Vec<u8> = vec![
1189 0x41, 0x75, 0x74, 0x6f, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2d, 0x47, 0x6f, 0x73, 0x73, 0x69,
1190 0x70, 0x3a, 0x20, 0xc8, 0x84, 0x01, 0x42, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x25, 0x25, 0x25,
1191 0x25, 0x42, 0x25, 0x3f, 0x21, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
1192 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x00, 0x40, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
1193 0x25, 0x22, 0x6b, 0x25, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1194 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x25, 0x25, 0x25, 0x25,
1195 0x25, 0x25, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x25, 0x25, 0x25, 0x25, 0x25,
1196 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25,
1197 ];
1198
1199 AutocryptHeaders::from_bytes(&data).expect("parses");
1200 }
1201}