apt_swarm/
pgp.rs

1use crate::errors::*;
2use sequoia_openpgp::cert::prelude::*;
3use sequoia_openpgp::parse::{PacketParser, Parse};
4use sequoia_openpgp::policy::NullPolicy;
5use sequoia_openpgp::{Cert, Fingerprint, KeyHandle, KeyID};
6
7#[derive(Debug, Clone)]
8pub struct Subkey {
9    pub fingerprint: sequoia_openpgp::Fingerprint,
10    pub is_primary: bool,
11    pub for_authentication: bool,
12    pub for_certification: bool,
13    pub for_signing: bool,
14    pub for_storage_encryption: bool,
15    pub for_transport_encryption: bool,
16}
17
18#[derive(Debug, Clone)]
19pub struct SigningKey {
20    pub fingerprint: sequoia_openpgp::Fingerprint,
21    pub cert: Cert,
22    pub uids: Vec<String>,
23    pub key_handles: Vec<(KeyHandle, Fingerprint)>,
24    pub subkeys: Vec<Subkey>,
25}
26
27impl SigningKey {
28    pub fn hex_fingerprint(&self) -> String {
29        format!("{:X}", self.fingerprint)
30    }
31
32    pub fn register_keyhandles(&mut self, fp: Fingerprint) {
33        let keyid = KeyID::from(&fp);
34        self.key_handles.push((KeyHandle::KeyID(keyid), fp.clone()));
35        self.key_handles
36            .push((KeyHandle::Fingerprint(fp.clone()), fp));
37    }
38}
39
40pub fn load(keyring: &[u8]) -> Result<Vec<SigningKey>> {
41    let ppr = PacketParser::from_bytes(&keyring)?;
42
43    let mut out = Vec::new();
44    for certo in CertParser::from(ppr) {
45        let cert = certo.context("Error reading pgp key")?;
46
47        let fingerprint = cert.fingerprint();
48
49        let mut signing_key = SigningKey {
50            fingerprint,
51            cert: cert.clone(),
52            uids: Vec::new(),
53            key_handles: Vec::new(),
54            subkeys: Vec::new(),
55        };
56
57        let p = &NullPolicy::new();
58        for key in cert.keys().with_policy(p, None) {
59            // TODO: we should probably also track and display encryption-only keys, for transparency
60            if key.for_signing() {
61                signing_key.register_keyhandles(key.fingerprint());
62            }
63
64            signing_key.subkeys.push(Subkey {
65                fingerprint: key.fingerprint(),
66                is_primary: key.primary(),
67                for_authentication: key.for_authentication(),
68                for_certification: key.for_certification(),
69                for_signing: key.for_signing(),
70                for_storage_encryption: key.for_storage_encryption(),
71                for_transport_encryption: key.for_transport_encryption(),
72            });
73        }
74
75        for ua in cert.userids() {
76            signing_key.uids.push(ua.userid().to_string());
77        }
78
79        out.push(signing_key);
80    }
81
82    Ok(out)
83}