1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
use std::collections::HashSet;
use std::io;
use std::io::BufRead;
use std::io::Read;
use std::io::Write;

use failure::bail;
use failure::ensure;
use failure::err_msg;
use failure::format_err;
use failure::Error;

use crate::keyring::Keyring;
use crate::packets::SignatureType;

/// Verify the data in a document
///
/// Note that some data may be written out before the signature is verified,
/// and you must not process this until the method has returned success.
///
/// # Example
///
/// ```rust,no_run
/// use std::io::{stdin, stdout, BufReader, Seek, SeekFrom};
///
/// fn check_stdin(keyring: &gpgrv::Keyring) {
///     let mut temp = tempfile::tempfile().unwrap();
///     gpgrv::verify_message(BufReader::new(stdin()), &mut temp, keyring)
///         .expect("verification");
///     temp.seek(SeekFrom::Start(0)).unwrap();
///     std::io::copy(&mut temp, &mut stdout()).unwrap();
/// }
/// ```
pub fn verify_message<R: BufRead, W: Write>(
    from: R,
    to: W,
    keyring: &Keyring,
) -> Result<(), Error> {
    let doc = crate::read_doc(from, io::BufWriter::new(to))?;

    let body = doc
        .body
        .ok_or_else(|| err_msg("document wasn't a message (i.e. there was no body)"))?;

    let signatures_of_correct_type: Vec<_> = doc
        .signatures
        .into_iter()
        .filter(|sig| body.sig_type == sig.sig_type)
        .collect();

    ensure!(
        !signatures_of_correct_type.is_empty(),
        "no signatures are of the correct type"
    );

    crate::any_signature_valid(keyring, &signatures_of_correct_type, &body.digest)
        .map_err(|errors| format_err!("no valid signatures: {:?}", errors))
}

pub fn verify_detached<S: BufRead, M: Read>(
    signature: S,
    mut message: M,
    keyring: &Keyring,
) -> Result<(), Error> {
    let doc = crate::read_doc(signature, iowrap::Ignore::new())?;
    if doc.body.is_some() {
        bail!("detached signature was a message");
    }

    let signatures = doc.signatures;

    let mut body_modes = HashSet::with_capacity(4);

    if signatures.is_empty() {
        bail!("no signatures in signature file")
    }

    for sig in &signatures {
        body_modes.insert((sig.sig_type, sig.hash_alg));
    }

    let (sig_type, hash_type) = *match body_modes.len() {
        0 => unreachable!(),
        1 => body_modes.iter().next().unwrap(),
        _ => bail!(
            "unsupported: signatures with multiple modes: {:?}",
            body_modes
        ),
    };

    match sig_type {
        SignatureType::Binary => (),
        other => bail!("unsupported: detached signature of type: {:?}", other),
    }

    let mut digest = crate::load::digestable_for(hash_type)
        .ok_or_else(|| format_err!("unsuported: hash type {:?}", hash_type))?;

    let mut buf = [0u8; 8 * 1024];

    loop {
        let read = message.read(&mut buf)?;
        if 0 == read {
            break;
        }
        let buf = &buf[..read];
        digest.process(buf);
    }

    crate::any_signature_valid(keyring, &signatures, &digest)
        .map_err(|errors| format_err!("no valid signatures: {:?}", errors))
}