1use crate::config::Config;
2use crate::errors::*;
3use crate::pgp;
4use crate::pgp::SigningKey;
5use memchr::memchr;
6use sequoia_openpgp::packet::Signature;
7use sequoia_openpgp::types::SignatureType;
8use sequoia_openpgp::{Fingerprint, KeyHandle};
9use serde::{Deserialize, Serialize};
10use std::borrow::Cow;
11use std::collections::BTreeMap;
12
13#[derive(Debug, Clone)]
14pub struct Subkey {
15 pub parent: Fingerprint,
16 pub fingerprint: Fingerprint,
17}
18
19#[derive(Debug, Default, Clone)]
20pub struct Keyring {
21 pub keys: BTreeMap<Fingerprint, pgp::SigningKey>,
22 pub identifiers: BTreeMap<String, Subkey>,
23}
24
25impl Keyring {
26 pub fn load(config: &Config) -> Result<Self> {
27 let mut keyring = Keyring::default();
28 for repository in &config.data.repositories {
29 keyring.add_keyring(repository.keyring.as_bytes())?;
30 }
31 Ok(keyring)
32 }
33
34 pub fn new(keyring: &[u8]) -> Result<Self> {
35 let mut k = Keyring::default();
36 k.add_keyring(keyring)?;
37 Ok(k)
38 }
39
40 pub fn add_keyring(&mut self, keyring: &[u8]) -> Result<()> {
41 let keys = pgp::load(keyring)?;
42 for key in keys {
43 self.register_identifiers(&key);
44 let fingerprint = key.fingerprint.clone();
45 self.keys.insert(fingerprint, key);
46 }
47 Ok(())
48 }
49
50 pub fn register_identifiers(&mut self, key: &SigningKey) {
51 for (id, fp) in &key.key_handles {
52 let id = id.to_string();
53 trace!("Linking identifier for key {:X}: {id:?}", key.fingerprint);
54 self.identifiers.insert(
55 id,
56 Subkey {
57 parent: key.fingerprint.clone(),
58 fingerprint: fp.clone(),
59 },
60 );
61 }
62 }
63
64 pub fn all_fingerprints(&self) -> Vec<Fingerprint> {
65 self.keys
66 .values()
67 .flat_map(|k| &k.key_handles)
68 .flat_map(|(k, _)| {
69 if let KeyHandle::Fingerprint(fp) = k {
70 Some(fp.to_owned())
71 } else {
72 None
73 }
74 })
75 .collect()
76 }
77
78 pub fn find_signing_key(&self, sig: &Signature) -> Result<(&Fingerprint, &SigningKey)> {
79 for issuer in sig.get_issuers() {
80 debug!("Found issuer in signature packet: {issuer:?}");
81 if let Some(subkey) = self.identifiers.get(&issuer.to_string()) {
82 debug!("Found fingerprint for given issuer: {:?}", subkey.parent);
83 let key = self.keys.get(&subkey.parent).with_context(|| {
84 anyhow!(
85 "Failed to get signing key by fingerprint: {:?}",
86 subkey.parent
87 )
88 })?;
89 return Ok((&subkey.fingerprint, key));
90 }
91 }
92 bail!("Could not find key for given signature")
93 }
94
95 pub fn verify(&self, data: &[u8], sig: &Signature) -> Result<Fingerprint> {
97 let (signer_fp, signing_key) = self.find_signing_key(sig)?;
98
99 let body: Cow<[u8]> = match sig.typ() {
100 SignatureType::Binary => Cow::Borrowed(data),
101 SignatureType::Text => {
102 let mut out = Vec::new();
103
104 let mut bytes = data;
105 while !bytes.is_empty() {
106 if let Some(idx) = memchr(b'\n', bytes) {
107 let line = &bytes[..idx];
108 bytes = &bytes[idx + 1..];
110
111 out.extend(line);
112 if !bytes.is_empty() {
113 out.extend(b"\r\n");
114 }
115 } else {
116 out.extend(bytes);
117 bytes = &[];
118 }
119 }
120
121 Cow::Owned(out)
122 }
123 unsupported => bail!("Unsupported signature type: {unsupported:?}"),
124 };
125
126 for key in signing_key.cert.keys() {
127 let key = key.key();
128
129 let key_fp = key.fingerprint();
131 debug!("Attempting verification with {:X}", key_fp);
132 if key_fp != *signer_fp {
133 debug!("This key was not the issuer, skipping: {:?}", key_fp);
134 continue;
135 }
136
137 sig.clone()
138 .verify_message(key, body)
139 .context("Failed to verify message")?;
140 debug!("Successfully verified signature");
141 return Ok(key_fp);
142 }
143
144 bail!("Signature could not be verified with any of the pgp certificates public keys")
145 }
146
147 pub fn generate_report(&self) -> Result<KeyringReport> {
148 Ok(KeyringReport {
149 keys: self.keys.values().map(KeyReport::generate).collect(),
150 })
151 }
152}
153
154#[derive(Debug, PartialEq, Serialize, Deserialize)]
155pub struct KeyringReport {
156 pub keys: Vec<KeyReport>,
157}
158
159#[derive(Debug, PartialEq, Serialize, Deserialize)]
160pub struct KeyReport {
161 pub primary_fingerprint: String,
162 pub uids: Vec<String>,
163 pub subkeys: Vec<SubkeyReport>,
164}
165
166impl KeyReport {
167 pub fn generate(key: &pgp::SigningKey) -> Self {
168 KeyReport {
169 primary_fingerprint: format!("{:X}", key.fingerprint),
170 uids: key.uids.clone(),
171 subkeys: key.subkeys.iter().map(SubkeyReport::generate).collect(),
172 }
173 }
174}
175
176#[derive(Debug, PartialEq, Serialize, Deserialize)]
177pub struct SubkeyReport {
178 pub fingerprint: String,
179 pub is_primary: bool,
180 pub for_authentication: bool,
181 pub for_certification: bool,
182 pub for_signing: bool,
183 pub for_storage_encryption: bool,
184 pub for_transport_encryption: bool,
185}
186
187impl SubkeyReport {
188 pub fn generate(key: &pgp::Subkey) -> Self {
189 SubkeyReport {
190 fingerprint: format!("{:X}", key.fingerprint),
191 is_primary: key.is_primary,
192 for_authentication: key.for_authentication,
193 for_certification: key.for_certification,
194 for_signing: key.for_signing,
195 for_storage_encryption: key.for_storage_encryption,
196 for_transport_encryption: key.for_transport_encryption,
197 }
198 }
199}