1use std::{
2 collections::{BTreeMap, BTreeSet, btree_map::Entry, HashSet},
3 env,
4 fmt,
5 fs,
6 io::{self, Read, Write},
7 path::{Path, PathBuf},
8 time::SystemTime,
9};
10
11use git2::{
12 Repository,
13 Oid,
14};
15use serde::{Deserialize, Serialize};
16
17use sequoia_openpgp::{
18 self as openpgp,
19 Cert,
20 Fingerprint,
21 KeyHandle,
22 Packet,
23 cert::{
24 amalgamation::ValidAmalgamation,
25 prelude::{SubordinateKeyAmalgamation, UserIDAmalgamation},
26 raw::{RawCert, RawCertParser},
27 },
28 packet::{
29 Signature,
30 UserID,
31 key::PublicParts,
32 },
33 parse::Parse,
34 parse::{stream::*},
35 policy::StandardPolicy,
36 serialize::Serialize as _,
37 types::SignatureType,
38};
39
40use crate::{
41 Error,
42 Result,
43 utils::prune_cert,
44 utils::serialize_packet,
45 utils::serialize_signature,
46};
47
48const TRACE: bool = false;
50
51#[derive(Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
58pub struct Policy {
59 #[serde(default)]
65 version: usize,
66
67 #[serde(default)]
74 commit_goodlist: BTreeSet<String>,
75
76 #[serde(default)]
81 authorization: BTreeMap<String, Authorization>,
82}
83
84impl Policy {
85 fn working_dir_policy_file() -> Result<PathBuf> {
88 let git = git2::Repository::discover(env::current_dir()?)?;
89 if let Some(wd) = git.workdir() {
90 Ok(wd.join("openpgp-policy.toml"))
91 } else {
92 Err(Error::InvalidOperation("doesn't work on bare repos".into()))
93 }
94 }
95
96 pub fn parse_bytes<D: AsRef<[u8]>>(bytes: D) -> Result<Self> {
97 let bytes = bytes.as_ref();
98 let s = std::str::from_utf8(bytes)
99 .map_err(|e| Error::StorageError(e.to_string()))?;
100 let policy = toml::from_str(s)
101 .map_err(|e| Error::StorageError(e.to_string()))?;
102 Ok(policy)
103 }
104
105 pub fn read_file<P: AsRef<Path>>(path: P) -> Result<Policy> {
107 let path = path.as_ref();
108 let mut f = fs::File::open(path)?;
109
110 let mut s = String::new();
111 f.read_to_string(&mut s)?;
112 let p: Policy =
113 toml::from_str(&s).map_err(|e| Error::StorageError(e.to_string()))?;
114
115 Ok(p)
116 }
117
118 pub fn read_file_or_default<P: AsRef<Path>>(path: P) -> Result<Policy> {
120 let path = path.as_ref();
121 let mut f = match fs::File::open(path) {
122 Ok(f) => f,
123 Err(e) => if e.kind() == io::ErrorKind::NotFound {
124 return Ok(Policy::default());
125 } else {
126 return Err(e.into());
127 },
128 };
129
130 let mut s = String::new();
131 f.read_to_string(&mut s)?;
132 let p: Policy =
133 toml::from_str(&s).map_err(|e| Error::StorageError(e.to_string()))?;
134
135 Ok(p)
136 }
137
138 pub fn read_from_working_dir() -> Result<Policy> {
143 Self::read_file_or_default(&Self::working_dir_policy_file()?)
144 }
145
146 pub fn read_bytes_from_commit(git: &Repository, commit: &Oid)
148 -> Result<Vec<u8>>
149 {
150 tracer!(TRACE, "Policy::read_bytes_from_commit");
151 t!("(_, {})", commit);
152
153 let commit = git.find_commit(commit.clone())?;
154 let tree = commit.tree()?;
155 let result = if let Some(entry) = tree.get_name("openpgp-policy.toml") {
156 Ok(entry.to_object(&git)?.peel_to_blob()?.content().to_vec())
157 } else {
158 Err(Error::MissingPolicy(commit.id()))
159 };
160 result
161 }
162
163 pub fn read_from_commit(git: &Repository, commit: &Oid) -> Result<Self> {
165 Self::parse_bytes(Self::read_bytes_from_commit(git, commit)?)
166 }
167
168 pub fn write<P: AsRef<Path>>(&self, path: P) -> Result<()> {
170 let path = path.as_ref();
171 let mut new =
172 tempfile::NamedTempFile::new_in(path.parent().unwrap())?;
173
174 new.write_all(toml::to_string_pretty(&self)
175 .map_err(|e| Error::StorageError(e.to_string()))?
176 .as_bytes())?;
177
178 new.persist(path).map_err(|e| Error::StorageError(e.to_string()))?;
179
180 Ok(())
181 }
182
183 pub fn write_to_working_dir(&self) -> Result<()> {
185 self.write(&Self::working_dir_policy_file()?)
186 }
187
188 pub fn version(&self) -> usize {
190 self.version
191 }
192
193 pub fn commit_goodlist(&self) -> &BTreeSet<String> {
200 &self.commit_goodlist
201 }
202
203 pub fn commit_goodlist_mut(&mut self) -> &mut BTreeSet<String> {
210 &mut self.commit_goodlist
211 }
212
213 pub fn authorization(&self) -> &BTreeMap<String, Authorization> {
218 &self.authorization
219 }
220
221 pub fn authorization_mut(&mut self) -> &mut BTreeMap<String, Authorization> {
226 &mut self.authorization
227 }
228
229 pub fn diff<'f, 't>(&'f self, other: &'t Policy) -> Result<Diff<'f, 't>> {
231 let mut changes = Vec::new();
232
233 if self.version != other.version {
235 changes.push(Change::VersionChange {
236 from: self.version,
237 to: other.version,
238 });
239 }
240
241 for c in self.commit_goodlist.difference(&other.commit_goodlist) {
243 changes.push(Change::UngoodlistCommit(c.parse()?));
244 }
245 for c in other.commit_goodlist.difference(&self.commit_goodlist) {
246 changes.push(Change::GoodlistCommit(c.parse()?));
247 }
248
249 let null_auth = Authorization::default();
252
253 for (k, from) in self.authorization.iter()
255 .filter(|(k, _)| ! other.authorization.contains_key(k.as_str()))
256 {
257 from.diff(&null_auth, k.into(), &mut changes);
259
260 changes.push(Change::RetireUser(k.into()));
262 }
263
264 for (k, from, to) in self.authorization.iter()
266 .filter_map(|(k, from)| other.authorization.get(k)
267 .map(|to| (k, from, to)))
268 {
269 from.diff(to, k.into(), &mut changes);
270 }
271
272 for (k, to) in other.authorization.iter()
274 .filter(|(k, _)| ! self.authorization.contains_key(k.as_str()))
275 {
276 changes.push(Change::AddUser(k.into()));
278
279 null_auth.diff(to, k.into(), &mut changes);
281 }
282
283 Ok(Diff {
284 version: DIFF_JSON_VERSION,
285 from: self,
286 changes,
287 to: other,
288 })
289 }
290
291 pub fn verify(&self, git: &Repository, commit_id: &Oid,
301 commit_policy: &Policy,
302 signer_keys: &mut BTreeSet<Fingerprint>,
303 primary_uids: &mut BTreeSet<UserID>)
304 -> Result<Vec<Result<(String, Signature, Cert, Fingerprint)>>>
305 {
306 tracer!(TRACE, "Policy::verify");
307 t!("verify(_, {})", commit_id);
308
309 if self.commit_goodlist.contains(&commit_id.to_string()) {
310 Ok(vec![])
311 } else {
312 let Ok((sig, data)) = git.extract_signature(commit_id, None)
313 else {
314 return Ok(vec![Err(Error::MissingSignature(commit_id.clone()))]);
315 };
316 t!("{} bytes of signature", sig.len());
317
318 self.verify_(&sig[..], &data[..],
333 commit_policy,
334 None,
335 signer_keys,
336 primary_uids,
337 Error::MissingSignature(commit_id.clone()),
338 Right::SignCommit)
339 }
340 }
341
342 pub fn verify_archive<T, S>(&self,
343 signature: S,
344 archive: T)
345 -> Result<Vec<Result<(String, Signature, Cert,
346 Fingerprint)>>>
347 where
348 T: AsRef<[u8]>,
349 S: AsRef<[u8]>,
350 {
351 let mut signer_keys = Default::default();
352 let mut primary_uids = Default::default();
353 self.verify_(signature.as_ref(),
354 archive.as_ref(),
355 self,
356 None,
357 &mut signer_keys,
358 &mut primary_uids,
359 Error::MissingDataSignature("Tarball".into()),
360 Right::SignArchive)
361 }
362
363 fn verify_(&self,
364 signature: &[u8],
365 data: &[u8],
366 commit_policy: &Policy,
367 commit_time: Option<SystemTime>,
368 signer_keys: &mut BTreeSet<Fingerprint>,
369 primary_uids: &mut BTreeSet<UserID>,
370 missing_signature_error: Error,
371 require_right: Right)
372 -> Result<Vec<Result<(String, Signature, Cert, Fingerprint)>>>
373 {
374 tracer!(TRACE, "Policy::verify_");
375 t!("verify_({} bytes, {} bytes, _, {:?}, _, _, {}, {})",
376 signature.len(), data.len(), commit_time,
377 missing_signature_error, require_right);
378
379 let p = &StandardPolicy::new();
380 let h = Helper {
381 parent_policy: self,
382 child_policy: commit_policy,
383 signer_keys,
384 primary_uids,
385 results: Default::default(),
386 };
387
388 let mut v = DetachedVerifierBuilder::from_bytes(signature)?
389 .with_policy(p, commit_time, h)?;
390 v.verify_bytes(data)?;
391 let h = v.into_helper();
392 let signature_results = h.results;
393
394 if signature_results.is_empty() {
395 t!("no signatures found!");
396 return Ok(vec![Err(missing_signature_error)]);
397 }
398
399 if signature_results.iter().all(|r| r.is_err()) {
400 let e = signature_results.into_iter().find(|r| r.is_err())
401 .expect("not empty and not all were ok");
402 return Err(e.unwrap_err());
403 }
404
405 let diff = self.diff(commit_policy)?;
409
410 let mut results: Vec<Result<(String, Signature, Cert, Fingerprint)>>
411 = Vec::new();
412 for r in signature_results {
413 match r {
414 Ok((sig, cert, signer_fpr)) => {
415 let cert_fp = cert.fingerprint();
418 for (name, a) in self.authorization.iter()
419 .filter(|(_, a)| a.certs().into_iter()
420 .flat_map(|r| r.into_iter())
421 .flat_map(|r| r.into_iter())
422 .any(|c| c.fingerprint() == cert_fp))
423 {
424 t!("{}: valid signature", name);
425 let r = a.rights();
426 t!("{}: {:?}", name, r);
427
428 if let Err(e) = r.assert(require_right)
429 .and_then(|_| diff.assert(&r))
430 {
431 results.push(Err(e));
432 } else {
433 results.push(
434 Ok((name.into(), sig.clone(), cert.clone(),
435 signer_fpr.clone())));
436 }
437 }
438 },
439 Err(e) => results.push(Err(e)),
440 }
441 }
442
443 Ok(results)
444 }
445}
446
447struct Helper<'p> {
449 parent_policy: &'p Policy,
450 child_policy: &'p Policy,
451 signer_keys: &'p mut BTreeSet<openpgp::Fingerprint>,
453 primary_uids: &'p mut BTreeSet<UserID>,
454 results: Vec<Result<(Signature, Cert, Fingerprint)>>,
455}
456
457impl Helper<'_> {
458 fn handle_result(&mut self, r: VerificationResult) {
459 tracer!(TRACE, "VerificationHelper::handle_result");
460 match r {
461 Ok(sig) => {
462 self.signer_keys.insert(sig.ka.key().fingerprint());
463
464 if let Ok(userid) = sig.ka.valid_cert().primary_userid() {
465 let u = userid.userid();
466 if ! self.primary_uids.contains(u) {
467 self.primary_uids.insert(u.clone());
468 }
469 }
470
471 self.results.push(
472 Ok((sig.sig.clone(), sig.ka.cert().clone(),
473 sig.ka.key().fingerprint().clone())));
474 },
475 Err(e) => {
476 t!("Signature verification failed: {}", e);
477 use VerificationError::*;
478 self.results.push(Err(match e {
479 MalformedSignature { error, .. } =>
480 Error::BadSignature(error.to_string()),
481 MissingKey { sig } => {
482 let mut issuers = sig.get_issuers();
483 if issuers.is_empty() {
484 Error::BadSignature(
485 "No issuer information".into())
486 } else {
487 Error::MissingKey(issuers.remove(0))
488 }
489 },
490 UnboundKey { cert, error, .. } =>
491 Error::BadKey(cert.key_handle(),
492 error.to_string()),
493 BadKey { ka, error, .. } =>
494 Error::BadKey(ka.cert().key_handle(),
495 error.to_string()),
496 BadSignature { error, .. } =>
497 Error::BadSignature(error.to_string()),
498 UnknownSignature { sig, .. } =>
499 Error::BadSignature(sig.error().to_string()),
500 u =>
501 Error::BadSignature(u.to_string()),
502 }));
503 },
504 }
505 }
506}
507
508impl VerificationHelper for Helper<'_> {
509 fn get_certs(&mut self, ids: &[KeyHandle]) -> openpgp::Result<Vec<Cert>> {
510 tracer!(TRACE, "VerificationHelper::get_certs");
511 t!("get_certs({:?})", ids);
512
513 let mut matches: BTreeMap<Fingerprint, Cert> = BTreeMap::new();
514
515 let mut parent: BTreeMap<Fingerprint, Vec<RawCert>> = BTreeMap::new();
516
517 for (name, auth) in self.parent_policy.authorization.iter() {
518 for cert in auth.certs()? {
519 let cert = cert?;
520
521 let entry = parent.entry(cert.fingerprint());
523 match entry {
524 Entry::Occupied(mut oe) => {
525 oe.get_mut().push(cert.clone());
526 }
527 Entry::Vacant(ve) => {
528 ve.insert(vec![ cert.clone() ]);
529 }
530 }
531
532 if cert.keys().any(
533 |k| ids.iter().any(|i| i.aliases(&k.key_handle())))
534 {
535 t!("Signature could be from {}", name);
536
537 let cert = Cert::try_from(cert)?;
538
539 let entry = matches.entry(cert.fingerprint());
540 match entry {
541 Entry::Occupied(mut oe) => {
542 let c: &mut Cert = oe.get_mut();
543 *c = c.clone().merge_public(cert)?;
544 }
545 Entry::Vacant(ve) => {
546 ve.insert(cert);
547 }
548 }
549 }
550 }
551 }
552
553 if self.parent_policy != self.child_policy {
559 let merge = |parent: Cert, child: Cert| -> Result<Cert> {
562 let child = child.into_packets().filter(|p| {
563 if let Packet::Signature(sig) = p {
564 ! matches!(sig.typ(),
565 SignatureType::KeyRevocation
566 | SignatureType::SubkeyRevocation
567 | SignatureType::CertificationRevocation)
568 } else {
569 true
570 }
571 });
572
573 Ok(parent.insert_packets(child)?.0)
574 };
575
576 for (name, auth) in self.child_policy.authorization.iter() {
577 let child_certs = if let Ok(certs) = auth.certs() {
578 certs
579 } else {
580 continue;
582 };
583
584 for child_cert in child_certs {
585 let child_cert = if let Ok(cert) = child_cert {
586 cert
587 } else {
588 continue;
590 };
591
592 let fpr = child_cert.fingerprint();
593 if let Some(cert) = matches.get_mut(&fpr) {
594 t!("Updating {}", fpr);
595
596 let child_cert = if let Ok(cert)
597 = Cert::try_from(child_cert)
598 {
599 cert
600 } else {
601 continue;
603 };
604
605 if let Ok(merged) = merge(cert.clone(), child_cert) {
606 *cert = merged;
607 }
608 } else {
609 if child_cert.keys().any(
610 |k| ids.iter().any(|i| i.aliases(&k.key_handle())))
611 {
612 t!("Signature could be from {}", name);
613
614 if let Some(certs)
620 = parent.get(&child_cert.fingerprint())
621 {
622 if let Ok(child_cert) = Cert::try_from(child_cert) {
623 let mut parent: Option<Cert> = None;
624 for c in certs.into_iter() {
625 let c = if let Ok(c) = Cert::try_from(c) {
626 c
627 } else {
628 continue;
629 };
630 if let Some(parent) = parent.as_mut() {
631 if let Ok(merged) =
632 parent.clone().merge_public(c)
633 {
634 *parent = merged;
635 }
636 } else {
637 parent = Some(c);
638 }
639 }
640
641 let parent = if let Some(parent) = parent {
642 parent
643 } else {
644 continue;
645 };
646
647 if let Ok(merged) = merge(parent, child_cert) {
649 matches.insert(
650 merged.fingerprint(), merged);
651 }
652 }
653 }
654 }
655 }
656 }
657 }
658 }
659
660 Ok(matches.into_values().collect())
661 }
662 fn check(&mut self, structure: MessageStructure) -> openpgp::Result<()> {
663 tracer!(TRACE, "VerificationHelper::get_certs");
664 if false {
665 t!("check({:?})", structure);
666 }
667
668 for (i, layer) in structure.into_iter().enumerate() {
669 match layer {
670 MessageLayer::SignatureGroup { results } if i == 0 => {
671 for r in results {
672 self.handle_result(r);
673 }
674 },
675 _ => return Err(Error::BadSignature(
676 "Unexpected signature structure".into()).into()),
677 }
678 }
679 Ok(())
680 }
681}
682
683#[derive(Default, Clone, Deserialize, Serialize, PartialEq, Eq)]
684pub struct Authorization {
685 #[serde(default, skip_serializing_if = "bool_is_false")]
686 pub sign_commit: bool,
687 #[serde(default, skip_serializing_if = "bool_is_false")]
688 pub sign_tag: bool,
689 #[serde(default, skip_serializing_if = "bool_is_false")]
690 pub sign_archive: bool,
691 #[serde(default, skip_serializing_if = "bool_is_false")]
692 pub add_user: bool,
693 #[serde(default, skip_serializing_if = "bool_is_false")]
694 pub retire_user: bool,
695 #[serde(default, skip_serializing_if = "bool_is_false")]
696 pub audit: bool,
697 pub keyring: String,
698}
699
700fn bool_is_false(b: &bool) -> bool {
701 *b == false
702}
703
704impl Authorization {
705 pub fn rights(&self) -> Rights {
706 use Right::*;
707
708 let mut r = BTreeSet::default();
709
710 if self.sign_commit {
711 r.insert(SignCommit);
712 }
713 if self.sign_tag {
714 r.insert(SignTag);
715 }
716 if self.sign_archive {
717 r.insert(SignArchive);
718 }
719 if self.add_user {
720 r.insert(AddUser);
721 }
722 if self.retire_user {
723 r.insert(RetireUser);
724 }
725 if self.audit {
726 r.insert(Audit);
727 }
728
729 Rights(r)
730 }
731
732 pub fn certs(&self) -> Result<impl Iterator<Item = openpgp::Result<RawCert>>> {
733 Ok(RawCertParser::from_bytes(self.keyring.as_bytes())?)
734 }
735
736 pub fn set_certs(&mut self, certs: Vec<openpgp::Cert>) -> Result<()> {
737 self.set_certs_filter(certs, |_| true, |_| true)
738 }
739
740 pub fn set_certs_filter<S, U>(&mut self, certs: Vec<openpgp::Cert>,
741 mut subkeys: S,
742 mut userids: U)
743 -> Result<()>
744 where
745 S: FnMut(&SubordinateKeyAmalgamation<PublicParts>) -> bool,
746 U: FnMut(&UserIDAmalgamation) -> bool,
747 {
748 let mut keyring = Vec::new();
749
750 for c in certs {
751 let c = prune_cert(c, &mut subkeys, &mut userids)?;
752 c.armored().export(&mut keyring)?;
753 }
754
755 self.keyring = String::from_utf8(keyring)
756 .map_err(|e| Error::StorageError(e.to_string()))?;
757 Ok(())
758 }
759
760 fn diff(&self, other: &Authorization, name: String,
763 changes: &mut Vec<Change>)
764 {
765 let (from, to) = (self, other);
766
767 if from.sign_commit && ! to.sign_commit {
769 changes.push(Change::RemoveRight(name.clone(), Right::SignCommit));
770 }
771 if from.sign_tag && ! to.sign_tag {
772 changes.push(Change::RemoveRight(name.clone(), Right::SignTag));
773 }
774 if from.sign_archive && ! to.sign_archive {
775 changes.push(Change::RemoveRight(name.clone(), Right::SignArchive));
776 }
777 if from.add_user && ! to.add_user {
778 changes.push(Change::RemoveRight(name.clone(), Right::AddUser));
779 }
780 if from.retire_user && ! to.retire_user {
781 changes.push(Change::RemoveRight(name.clone(), Right::RetireUser));
782 }
783 if from.audit && ! to.audit {
784 changes.push(Change::RemoveRight(name.clone(), Right::Audit));
785 }
786
787 if ! from.sign_commit && to.sign_commit {
789 changes.push(Change::AddRight(name.clone(), Right::SignCommit));
790 }
791 if ! from.sign_tag && to.sign_tag {
792 changes.push(Change::AddRight(name.clone(), Right::SignTag));
793 }
794 if ! from.sign_archive && to.sign_archive {
795 changes.push(Change::AddRight(name.clone(), Right::SignArchive));
796 }
797 if ! from.add_user && to.add_user {
798 changes.push(Change::AddRight(name.clone(), Right::AddUser));
799 }
800 if ! from.retire_user && to.retire_user {
801 changes.push(Change::AddRight(name.clone(), Right::RetireUser));
802 }
803 if ! from.audit && to.audit {
804 changes.push(Change::AddRight(name.clone(), Right::Audit));
805 }
806
807 if self.keyring != other.keyring {
809 fn parse_keyring<'a>(name: &str, keyring: &'a str)
815 -> BTreeMap<Fingerprint, Vec<RawCert<'a>>>
816 {
817 match RawCertParser::from_bytes(keyring) {
818 Err(err) => {
819 eprintln!("Parsing {}'s keyring: {}", name, err);
820 Default::default()
821 }
822 Ok(certs) => {
823 let certs = certs.into_iter()
824 .filter_map(|cert| {
825 match cert {
826 Err(err) => {
827 eprintln!("Parsing certificate from {}'s keyring: {}",
828 name, err);
829 None
830 }
831 Ok(cert) => Some(cert),
832 }
833 });
834
835 let mut map: BTreeMap<Fingerprint, Vec<RawCert>> = BTreeMap::new();
836 for cert in certs {
837 let entry = map.entry(cert.fingerprint());
838 match entry {
839 Entry::Occupied(mut oe) => {
840 let oe: &mut Vec<RawCert> = oe.get_mut();
841 oe.push(cert);
842 }
843 Entry::Vacant(ve) => {
844 ve.insert(vec![ cert ]);
845 }
846 }
847 }
848
849 map
850 }
851 }
852 }
853
854 let old = parse_keyring(&name, &self.keyring);
855 let new = parse_keyring(&name, &other.keyring);
856
857 let old_certs: BTreeSet<&Fingerprint> = old.keys().collect();
859 let new_certs: BTreeSet<&Fingerprint> = new.keys().collect();
860
861 for &removed in old_certs.difference(&new_certs) {
862 changes.push(Change::RemoveCert(name.clone(), removed.clone()));
863 }
864 for &added in new_certs.difference(&old_certs) {
865 changes.push(Change::AddCert(name.clone(), added.clone()));
866 }
867
868 for &fpr in old_certs.intersection(&new_certs) {
871 let old = old.get(fpr).expect("have it");
872 let new = new.get(fpr).expect("have it");
873
874 if old == new {
875 continue;
876 }
877
878 let into_packets = |certs: Vec<RawCert>| -> HashSet<(Packet, Signature)> {
881 let mut pairs: HashSet<(Packet, Signature)> = HashSet::new();
882
883 for cert in certs.into_iter() {
884 let mut packets = cert.packets();
885 let primary_key
886 = packets.next().expect("have a primary key");
887 let primary_key = match Packet::try_from(primary_key) {
888 Ok(p) => p,
889 Err(err) => {
890 eprintln!(
891 "Warning: {} has a corrupted primary key \
892 packet (skipped): {}",
893 cert.fingerprint(), err);
894 continue;
895 }
896 };
897
898 packets.fold(
899 primary_key,
900 |component, packet| {
901 let packet = match Packet::try_from(packet) {
902 Ok(p) => p,
903 Err(err) => {
904 eprintln!(
905 "Warning: {} has a corrupted packet \
906 (skipped): {}",
907 cert.fingerprint(), err);
908 return component;
909 }
910 };
911
912 match packet {
913 Packet::Signature(sig) => {
914 pairs.insert(
915 (component.clone(), sig.clone()));
916 component
917 }
918 Packet::Marker(_) => {
919 component
921 }
922 _ => {
923 packet.clone()
925 }
926 }
927 });
928 }
929
930 pairs
931 };
932
933 let old_packets = into_packets(old.clone());
934 let new_packets = into_packets(new.clone());
935
936 for (component, sig) in old_packets.difference(&new_packets) {
937 changes.push(Change::RemovePacket(name.clone(),
938 fpr.clone(),
939 component.clone(),
940 sig.clone()));
941 }
942 for (component, sig) in new_packets.difference(&old_packets) {
943 changes.push(Change::AddPacket(name.clone(),
944 fpr.clone(),
945 component.clone(),
946 sig.clone()));
947 }
948 }
949 }
950 }
951}
952
953static DIFF_JSON_VERSION: &'static str = "1.0.0";
956
957#[derive(Serialize)]
959pub struct Diff<'f, 't> {
960 version: &'static str,
961
962 pub from: &'f Policy,
963 pub changes: Vec<Change>,
964 pub to: &'t Policy,
965}
966
967impl Diff<'_, '_> {
968 fn assert(&self, r: &Rights) -> Result<()> {
969 for c in &self.changes {
970 c.assert(r)?;
971 }
972 Ok(())
973 }
974}
975
976use crate::utils::{serialize_fp, serialize_oid};
977
978#[derive(Clone, Serialize)]
979pub enum Change {
980 VersionChange {
981 from: usize,
982 to: usize,
983 },
984 GoodlistCommit(
985 #[serde(serialize_with = "serialize_oid")] Oid),
986 UngoodlistCommit(
987 #[serde(serialize_with = "serialize_oid")] Oid),
988
989 AddUser(String),
990 RetireUser(String),
991
992 AddRight(String, Right),
993 RemoveRight(String, Right),
994
995 AddCert(String,
996 #[serde(serialize_with = "serialize_fp")] Fingerprint),
997 RemoveCert(String,
998 #[serde(serialize_with = "serialize_fp")] Fingerprint),
999
1000 AddPacket(String,
1001 #[serde(serialize_with = "serialize_fp")] Fingerprint,
1003 #[serde(serialize_with = "serialize_packet")] Packet,
1005 #[serde(serialize_with = "serialize_signature")] Signature),
1007 RemovePacket(String,
1008 #[serde(serialize_with = "serialize_fp")] Fingerprint,
1010 #[serde(serialize_with = "serialize_packet")] Packet,
1012 #[serde(serialize_with = "serialize_signature")] Signature),
1014}
1015
1016impl Change {
1017 fn assert(&self, r: &Rights) -> Result<()> {
1018 use Change::*;
1019 match self {
1020 VersionChange { .. } => r.assert(Right::Audit),
1021 GoodlistCommit(_) => r.assert(Right::Audit),
1022 UngoodlistCommit(_) => r.assert(Right::Audit),
1023
1024 AddUser(_) => r.assert(Right::AddUser),
1026 RetireUser(_) => r.assert(Right::RetireUser),
1027 AddRight(_, right) =>
1028 r.assert(Right::AddUser).and_then(|_| r.assert(*right)),
1029 RemoveRight(_, right) =>
1030 r.assert(Right::RetireUser).and_then(|_| r.assert(*right)),
1031
1032 AddCert(_, _) => r.assert(Right::AddUser),
1034 RemoveCert(_, _) => r.assert(Right::RetireUser),
1035
1036 AddPacket(_, _, _, _) => Ok(()),
1038
1039 RemovePacket(_, fpr, _component, sig) => {
1041 if sig.get_issuers().into_iter()
1042 .any(|kh| kh.aliases(KeyHandle::from(fpr)))
1043 {
1044 r.assert(Right::RetireUser)
1047 } else {
1048 Ok(())
1049 }
1050 }
1051 }
1052 }
1053}
1054
1055#[derive(Debug)]
1056pub struct Rights(BTreeSet<Right>);
1057
1058impl Rights {
1059 fn assert(&self, r: Right) -> Result<()> {
1060 if ! self.0.contains(&r) {
1061 Err(Error::Unauthorized(format!("Right {} is missing", r)))
1062 } else {
1063 Ok(())
1064 }
1065 }
1066}
1067
1068#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq, PartialOrd, Ord)]
1069pub enum Right {
1070 SignCommit,
1071 SignTag,
1072 SignArchive,
1073 AddUser,
1074 RetireUser,
1075 Audit,
1076}
1077
1078impl fmt::Display for Right {
1079 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1080 use Right::*;
1081 match self {
1082 SignCommit => f.write_str("sign-commit"),
1083 SignTag => f.write_str("sign-tag"),
1084 SignArchive => f.write_str("sign-archive"),
1085 AddUser => f.write_str("add-user"),
1086 RetireUser => f.write_str("retire-user"),
1087 Audit => f.write_str("audit"),
1088 }
1089 }
1090}