1
use anyhow::anyhow;
2
use sequoia_openpgp::packet::{Signature, Tag};
3
use sequoia_openpgp::parse::stream::{
4
    DetachedVerifierBuilder, GoodChecksum, MessageLayer, MessageStructure, VerificationError,
5
    VerificationHelper,
6
};
7
use sequoia_openpgp::policy::{AsymmetricAlgorithm, StandardPolicy};
8
use sequoia_openpgp::KeyHandle;
9
use sequoia_openpgp::{cert::raw::RawCertParser, parse::Parse, Cert};
10
use serde::Serialize;
11
use std::path::Path;
12
use std::process::{Command, Stdio};
13

            
14
type Result<T> = anyhow::Result<T>;
15

            
16
fn read_keys(gpgdir: &Path) -> Result<Vec<u8>> {
17
    let gpgdir = gpgdir.to_str().unwrap();
18
    let output = Command::new("gpg")
19
        .args(["--batch", "--homedir", gpgdir, "--export", "-a"])
20
        .stdout(Stdio::piped())
21
        .stderr(Stdio::piped())
22
        .output()?;
23
    if !output.status.success() {
24
        return Err(anyhow!(
25
            "Could load public keys: {}",
26
            &String::from_utf8_lossy(&output.stderr)
27
        ));
28
    }
29
    Ok(output.stdout)
30
}
31

            
32
pub fn load_keys(gpgdir: &Path) -> Result<Vec<Cert>> {
33
    let keys = read_keys(gpgdir)?;
34
    let parser = RawCertParser::from_bytes(&keys)?;
35
    let mut certs = Vec::new();
36
    for cert in parser {
37
        let cert = cert?;
38
        certs.push(Cert::try_from(cert)?);
39
    }
40
    println!("Loaded {} keys", certs.len());
41
    Ok(certs)
42
}
43

            
44
#[derive(Serialize)]
45
pub struct PgpSignature {
46
    pub payload: Vec<u8>,
47
    pub signature: Vec<u8>,
48
}
49

            
50
pub struct ValidatedSignature {
51
    /// The parsed signature
52
    pub signature: Signature,
53
    /// The certificates corresponding to keys from the signature
54
    pub certificates: Vec<(KeyHandle, Cert)>,
55
}
56

            
57
impl ValidatedSignature {
58
    fn from_helper(helper: Helper) -> sequoia_openpgp::Result<Self> {
59
        if let Some(signature) = helper.signature {
60
            signature.typ();
61
            return Ok(Self {
62
                signature,
63
                certificates: helper
64
                    .used_certs
65
                    .into_iter()
66
                    .map(|(id, pos)| (id, helper.certs[pos].to_owned()))
67
                    .collect(),
68
            });
69
        }
70
        todo!()
71
    }
72
}
73

            
74
// Check a signature
75
// The required public key is retrieved from `certs`. If there is no
76
// matching key or the required certificate is missing, an error is
77
// returned.
78
pub fn check_signature(
79
    certs: &[Cert],
80
    signature: &PgpSignature,
81
) -> sequoia_openpgp::Result<ValidatedSignature> {
82
    let mut p = StandardPolicy::new();
83
    // accept all versions of the signature tag
84
    // PGP 2.6.x only accepts version 3 signatures.
85
    p.accept_packet_tag(Tag::Signature);
86
    // git uses SHA1 which is insecure in the standard policy
87
    p.accept_hash(sequoia_openpgp::types::HashAlgorithm::SHA1);
88
    p.accept_asymmetric_algo(AsymmetricAlgorithm::DSA1024);
89
    let builder = DetachedVerifierBuilder::from_bytes(&signature.signature)?;
90
    let h = Helper {
91
        certs,
92
        signature: None,
93
        used_certs: Vec::new(),
94
    };
95
    let mut v = builder.with_policy(&p, None, h)?;
96
    v.verify_bytes(&signature.payload)?;
97
    let helper = v.into_helper();
98
    ValidatedSignature::from_helper(helper)
99
}
100

            
101
struct Helper<'a> {
102
    certs: &'a [Cert],
103
    signature: Option<Signature>,
104
    // certificates that are used by the current signature
105
    // They are index into `certs`
106
    used_certs: Vec<(KeyHandle, usize)>,
107
}
108
impl<'a> VerificationHelper for Helper<'a> {
109
    /// This method will be called at most once per message.
110
    /// a missing certificate for an id is not an error
111
    fn get_certs(&mut self, ids: &[KeyHandle]) -> sequoia_openpgp::Result<Vec<Cert>> {
112
        self.used_certs.clear();
113
        let mut certs = Vec::with_capacity(ids.len());
114
        for id in ids {
115
            for (pos, cert) in self.certs.iter().enumerate() {
116
                if cert.key_handle() == *id {
117
                    self.used_certs.push((id.clone(), pos));
118
                    certs.push(cert.to_owned());
119
                }
120
            }
121
        }
122
        Ok(certs)
123
        // when debugging certs that cannot be found use the next line
124
        // Ok(self.certs.to_vec())
125
    }
126
    /// This method will be called at most once per message.
127
    fn check(&mut self, structure: MessageStructure) -> sequoia_openpgp::Result<()> {
128
        // in detached signatures, there is only one layer that is a
129
        // SignatureGroup
130
        for layer in structure {
131
            if let MessageLayer::SignatureGroup { results } = layer {
132
                let mut errors = Vec::new();
133
                for result in results {
134
                    if self.signature.is_some() {
135
                        return Err(anyhow!("Multiple signatures found."));
136
                    }
137
                    self.signature = check_result(&mut errors, result);
138
                }
139
                if !errors.is_empty() {
140
                    return Err(anyhow::Error::from(SignatureErrors(errors)));
141
                }
142
                return Ok(());
143
            }
144
        }
145
        panic!("MessageStructure should only have one layer with a SignatureGroup when `check` is called for a detached signature.");
146
    }
147
}
148

            
149
// Check the result of a signature match and place any errors into
150
// `result`.
151
fn check_result(
152
    errors: &mut Vec<anyhow::Error>,
153
    result: std::result::Result<GoodChecksum, VerificationError>,
154
) -> Option<Signature> {
155
    match result {
156
        Ok(checksum) => return Some(checksum.sig.clone()),
157
        Err(VerificationError::MalformedSignature { sig: _, error }) => {
158
            errors.push(error);
159
        }
160
        Err(VerificationError::MissingKey { sig }) => {
161
            errors.push(MissingKeyError(sig.clone()).into());
162
        }
163
        Err(VerificationError::UnboundKey {
164
            sig: _,
165
            cert: _,
166
            error,
167
        }) => {
168
            errors.push(error);
169
        }
170
        Err(VerificationError::BadKey {
171
            sig: _,
172
            ka: _,
173
            error,
174
        }) => {
175
            errors.push(error);
176
        }
177
        Err(VerificationError::BadSignature {
178
            sig: _,
179
            ka: _,
180
            error,
181
        }) => {
182
            errors.push(error);
183
        }
184
    }
185
    None
186
}
187

            
188
#[derive(Debug)]
189
pub struct SignatureErrors(pub Vec<anyhow::Error>);
190

            
191
impl std::error::Error for SignatureErrors {
192
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
193
        self.0.first().and_then(|e| e.source())
194
    }
195
}
196

            
197
impl std::fmt::Display for SignatureErrors {
198
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199
        for item in &self.0 {
200
            item.fmt(f)?;
201
        }
202
        Ok(())
203
    }
204
}
205

            
206
#[derive(Debug)]
207
pub struct MissingKeyError(Signature);
208

            
209
impl std::error::Error for MissingKeyError {}
210

            
211
impl MissingKeyError {
212
    pub fn missing_key(&self) -> Option<KeyHandle> {
213
        self.0.get_issuers().get(0).map(|k| k.to_owned())
214
    }
215
}
216

            
217
impl std::fmt::Display for MissingKeyError {
218
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219
        if let Some(issuer) = self.0.get_issuers().get(0) {
220
            write!(f, "Missing key: {}", issuer)
221
        } else {
222
            write!(f, "Missing key")
223
        }
224
    }
225
}