use std::cmp;
use std::collections::HashMap;
use std::io::{self, Read};
use std::path::Path;
use buffered_reader::BufferedReader;
use {
Error,
Fingerprint,
constants::{
DataFormat,
SymmetricAlgorithm,
},
packet::{
BodyLength,
ctb::CTB,
Key,
Literal,
one_pass_sig::OnePassSig3,
PKESK,
SKESK,
Tag,
},
KeyID,
Packet,
Result,
RevocationStatus,
packet,
packet::Signature,
TPK,
crypto::SessionKey,
serialize::Serialize,
};
use parse::{
Cookie,
PacketParser,
PacketParserBuilder,
PacketParserResult,
};
const TRACE : bool = false;
const BUFFER_SIZE: usize = 25 * 1024 * 1024;
pub struct Verifier<'a, H: VerificationHelper> {
helper: H,
tpks: Vec<TPK>,
keys: HashMap<KeyID, (usize, usize)>,
oppr: Option<PacketParserResult<'a>>,
sigs: Vec<Vec<Signature>>,
reserve: Option<Vec<u8>>,
time: time::Tm,
}
#[derive(Debug)]
pub enum VerificationResult<'a> {
GoodChecksum(Signature,
&'a TPK, &'a Key, Option<&'a Signature>, RevocationStatus<'a>),
MissingKey(Signature),
BadChecksum(Signature),
}
impl<'a> VerificationResult<'a> {
pub fn level(&self) -> usize {
use self::VerificationResult::*;
match self {
&GoodChecksum(ref sig, ..) => sig.level(),
&MissingKey(ref sig) => sig.level(),
&BadChecksum(ref sig) => sig.level(),
}
}
}
pub trait VerificationHelper {
fn get_public_keys(&mut self, &[KeyID]) -> Result<Vec<TPK>>;
fn check(&mut self, sigs: Vec<Vec<VerificationResult>>) -> Result<()>;
}
impl<'a, H: VerificationHelper> Verifier<'a, H> {
pub fn from_reader<R, T>(reader: R, helper: H, t: T)
-> Result<Verifier<'a, H>>
where R: io::Read + 'a, T: Into<Option<time::Tm>>
{
let t = t.into().unwrap_or_else(time::now_utc);
Verifier::from_buffered_reader(
Box::new(buffered_reader::Generic::with_cookie(reader, None,
Default::default())),
helper, t)
}
pub fn from_file<P, T>(path: P, helper: H, t: T) -> Result<Verifier<'a, H>>
where P: AsRef<Path>,
T: Into<Option<time::Tm>>
{
let t = t.into().unwrap_or_else(time::now_utc);
Verifier::from_buffered_reader(
Box::new(buffered_reader::File::with_cookie(path,
Default::default())?),
helper, t)
}
pub fn from_bytes<T>(bytes: &'a [u8], helper: H, t: T)
-> Result<Verifier<'a, H>>
where T: Into<Option<time::Tm>>
{
let t = t.into().unwrap_or_else(time::now_utc);
Verifier::from_buffered_reader(
Box::new(buffered_reader::Memory::with_cookie(bytes,
Default::default())),
helper, t)
}
pub fn helper_ref(&self) -> &H {
&self.helper
}
pub fn helper_mut(&mut self) -> &mut H {
&mut self.helper
}
pub fn into_helper(self) -> H {
self.helper
}
pub fn message_processed(&self) -> bool {
self.oppr.is_none()
}
pub(crate) fn from_buffered_reader(bio: Box<BufferedReader<Cookie> + 'a>,
helper: H, t: time::Tm)
-> Result<Verifier<'a, H>>
{
let mut ppr = PacketParser::from_buffered_reader(bio)?;
let mut v = Verifier {
helper: helper,
tpks: Vec::new(),
keys: HashMap::new(),
oppr: None,
sigs: Vec::new(),
reserve: None,
time: t,
};
let mut issuers = Vec::new();
let mut sigs = Vec::new();
while let PacketParserResult::Some(pp) = ppr {
if ! pp.possible_message() {
return Err(Error::MalformedMessage(
"Malformed OpenPGP message".into()).into());
}
match pp.packet {
Packet::OnePassSig(ref ops) =>
issuers.push(ops.issuer().clone()),
Packet::Literal(_) => {
v.tpks = v.helper.get_public_keys(&issuers)?;
for (i, tpk) in v.tpks.iter().enumerate() {
let can_sign = |key: &Key, sig: Option<&Signature>| -> bool {
if let Some(sig) = sig {
sig.key_flags().can_sign()
&& sig.signature_alive_at(t)
&& sig.key_alive_at(key, t)
} else {
false
}
};
if can_sign(tpk.primary(),
tpk.primary_key_signature()) {
v.keys.insert(tpk.keyid(), (i, 0));
}
for (j, skb) in tpk.subkeys().enumerate() {
let key = skb.subkey();
if can_sign(key, skb.binding_signature()) {
v.keys.insert(key.keyid(),
(i, j + 1));
}
}
}
v.oppr = Some(PacketParserResult::Some(pp));
v.finish_maybe()?;
for sig in sigs.into_iter() {
v.push_sig(Packet::Signature(sig))?;
}
return Ok(v);
},
_ => (),
}
let (p, ppr_tmp) = pp.recurse()?;
if let Packet::Signature(sig) = p {
if let Some(issuer) = sig.get_issuer() {
issuers.push(issuer);
} else {
issuers.push(KeyID::wildcard());
}
sigs.push(sig);
}
ppr = ppr_tmp;
}
Err(Error::MalformedMessage(
"Malformed OpenPGP message".into()).into())
}
fn push_sig(&mut self, p: Packet) -> Result<()> {
match p {
Packet::Signature(sig) => {
if self.sigs.is_empty() {
self.sigs.push(Vec::new());
}
if let Some(current_level) = self.sigs.iter().last()
.expect("sigs is never empty")
.get(0).map(|r| r.level())
{
if current_level != sig.level() {
self.sigs.push(Vec::new());
}
}
self.sigs.iter_mut().last()
.expect("sigs is never empty").push(sig);
},
_ => (),
}
Ok(())
}
fn finish_maybe(&mut self) -> Result<()> {
if let Some(PacketParserResult::Some(mut pp)) = self.oppr.take() {
let data_len = pp.data(BUFFER_SIZE + 1)?.len();
if data_len <= BUFFER_SIZE {
self.reserve = Some(pp.steal_eof()?);
let mut ppr = PacketParserResult::Some(pp);
while let PacketParserResult::Some(mut pp) = ppr {
if ! pp.possible_message() {
return Err(Error::MalformedMessage(
"Malformed OpenPGP message".into()).into());
}
let (p, ppr_tmp) = pp.recurse()?;
self.push_sig(p)?;
ppr = ppr_tmp;
}
let mut results = Vec::new();
for sigs in ::std::mem::replace(&mut self.sigs, Vec::new())
.into_iter().rev()
{
results.push(Vec::new());
for sig in sigs.into_iter() {
results.iter_mut().last().expect("never empty").push(
if let Some(issuer) = sig.get_issuer() {
if let Some((i, j)) = self.keys.get(&issuer) {
let tpk = &self.tpks[*i];
let (binding, revocation, key)
= tpk.keys_all().nth(*j).unwrap();
if sig.verify(key).unwrap_or(false) &&
sig.signature_alive_at(self.time)
{
VerificationResult::GoodChecksum
(sig, tpk, key, binding, revocation)
} else {
VerificationResult::BadChecksum(sig)
}
} else {
VerificationResult::MissingKey(sig)
}
} else {
VerificationResult::BadChecksum(sig)
}
)
}
}
self.helper.check(results)
} else {
self.oppr = Some(PacketParserResult::Some(pp));
Ok(())
}
} else {
panic!("No ppr.");
}
}
fn read_helper(&mut self, buf: &mut [u8]) -> Result<usize> {
if buf.len() == 0 {
return Ok(0);
}
if let Some(ref mut reserve) = self.reserve {
assert!(self.oppr.is_none());
let n = cmp::min(buf.len(), reserve.len());
&mut buf[..n].copy_from_slice(&reserve[..n]);
reserve.drain(..n);
return Ok(n);
}
if let Some(PacketParserResult::Some(mut pp)) = self.oppr.take() {
let data_len = pp.data(BUFFER_SIZE + buf.len())?.len();
if data_len <= BUFFER_SIZE {
self.oppr = Some(PacketParserResult::Some(pp));
self.finish_maybe()?;
self.read_helper(buf)
} else {
let n = cmp::min(buf.len(), data_len - BUFFER_SIZE);
let buf = &mut buf[..n];
let result = pp.read(buf);
self.oppr = Some(PacketParserResult::Some(pp));
Ok(result?)
}
} else {
panic!("No ppr.");
}
}
}
impl<'a, H: VerificationHelper> io::Read for Verifier<'a, H> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.read_helper(buf) {
Ok(n) => Ok(n),
Err(e) => match e.downcast::<io::Error>() {
Ok(e) => Err(e),
Err(e) => Err(io::Error::new(io::ErrorKind::Other,
e.compat())),
},
}
}
}
struct Transformer<'a> {
state: TransformationState,
sigs: Vec<Signature>,
reader: Box<'a + BufferedReader<()>>,
buffer: Vec<u8>,
}
#[derive(PartialEq, Debug)]
enum TransformationState {
Data,
Sigs,
Done,
}
impl<'a> Transformer<'a> {
fn new<'b>(signatures: Box<'b + BufferedReader<Cookie>>,
mut data: Box<'a + BufferedReader<()>>)
-> Result<Transformer<'a>>
{
let mut sigs = Vec::new();
let mut ppr = PacketParser::from_buffered_reader(signatures)?;
while let PacketParserResult::Some(pp) = ppr {
let (packet, ppr_) = pp.next()?;
ppr = ppr_;
match packet {
Packet::Signature(sig) => sigs.push(sig),
_ => return Err(Error::InvalidArgument(
format!("Not a signature packet: {:?}",
packet.tag())).into()),
}
}
let mut buf = Vec::new();
for (i, sig) in sigs.iter().rev().enumerate() {
let mut ops = Result::<OnePassSig3>::from(sig)?;
if i == sigs.len() - 1 {
ops.set_last(true);
}
ops.serialize(&mut buf)?;
}
let state = {
const HEADER_LEN: usize = 6;
let data_prefix = data.data_consume(512 - HEADER_LEN)?;
if data_prefix.len() < 512 - HEADER_LEN {
CTB::new(Tag::Literal).serialize(&mut buf)?;
let len = BodyLength::Full((data_prefix.len() + HEADER_LEN) as u32);
len.serialize(&mut buf)?;
let mut lit = Literal::new(DataFormat::Binary);
lit.serialize_headers(&mut buf, false)?;
buf.extend_from_slice(data_prefix);
TransformationState::Sigs
} else {
CTB::new(Tag::Literal).serialize(&mut buf)?;
let len = BodyLength::Partial(512);
len.serialize(&mut buf)?;
let mut lit = Literal::new(DataFormat::Binary);
lit.serialize_headers(&mut buf, false)?;
buf.extend_from_slice(&data_prefix[..512 - HEADER_LEN]);
TransformationState::Data
}
};
Ok(Self {
state: state,
sigs: sigs,
reader: data,
buffer: buf,
})
}
fn read_helper(&mut self, buf: &mut [u8]) -> Result<usize> {
if self.buffer.is_empty() {
self.state = match self.state {
TransformationState::Data => {
let mut s = buf.len().next_power_of_two();
if ! buf.len().is_power_of_two() {
s >>= 1;
}
const MAX_CHUNK_SIZE: usize = 1 << 22; if s > MAX_CHUNK_SIZE {
s = MAX_CHUNK_SIZE;
}
assert!(s <= ::std::u32::MAX as usize);
let data = self.reader.data(s)?;
if data.len() < s {
let len = BodyLength::Full(data.len() as u32);
len.serialize(&mut self.buffer)?;
let l = self.buffer.len();
self.buffer.resize(l + data.len(), 0);
&mut self.buffer[l..].copy_from_slice(data);
TransformationState::Sigs
} else {
let len = BodyLength::Partial(data.len() as u32);
len.serialize(&mut self.buffer)?;
let l = self.buffer.len();
self.buffer.resize(l + data.len(), 0);
&mut self.buffer[l..].copy_from_slice(data);
TransformationState::Data
}
},
TransformationState::Sigs => {
for sig in self.sigs.iter() {
sig.serialize(&mut self.buffer)?;
}
TransformationState::Done
},
TransformationState::Done =>
TransformationState::Done,
};
}
let n = cmp::min(buf.len(), self.buffer.len());
&mut buf[..n].copy_from_slice(&self.buffer[..n]);
self.buffer.drain(..n);
Ok(n)
}
}
impl<'a> io::Read for Transformer<'a> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.read_helper(buf) {
Ok(n) => Ok(n),
Err(e) => match e.downcast::<io::Error>() {
Ok(e) => Err(e),
Err(e) => Err(io::Error::new(io::ErrorKind::Other,
e.compat())),
},
}
}
}
pub struct DetachedVerifier {
}
impl DetachedVerifier {
pub fn from_reader<'a, 's, H, R, S, T>(signature_reader: S, reader: R,
helper: H, t: T)
-> Result<Verifier<'a, H>>
where R: io::Read + 'a, S: io::Read + 's, H: VerificationHelper,
T: Into<Option<time::Tm>>
{
let t = t.into().unwrap_or_else(time::now_utc);
Self::from_buffered_reader(
Box::new(buffered_reader::Generic::with_cookie(signature_reader, None,
Default::default())),
Box::new(buffered_reader::Generic::new(reader, None)),
helper, t)
}
pub fn from_file<'a, H, P, S, T>(signature_path: S, path: P,
helper: H, t: T)
-> Result<Verifier<'a, H>>
where P: AsRef<Path>, S: AsRef<Path>, H: VerificationHelper,
T: Into<Option<time::Tm>>
{
let t = t.into().unwrap_or_else(time::now_utc);
Self::from_buffered_reader(
Box::new(buffered_reader::File::with_cookie(signature_path,
Default::default())?),
Box::new(buffered_reader::File::open(path)?),
helper, t)
}
pub fn from_bytes<'a, 's, H, T>(signature_bytes: &'s [u8], bytes: &'a [u8],
helper: H, t: T)
-> Result<Verifier<'a, H>>
where H: VerificationHelper, T: Into<Option<time::Tm>>
{
let t = t.into().unwrap_or_else(time::now_utc);
Self::from_buffered_reader(
Box::new(buffered_reader::Memory::with_cookie(signature_bytes,
Default::default())),
Box::new(buffered_reader::Memory::new(bytes)),
helper, t)
}
pub(crate) fn from_buffered_reader<'a, 's, H>
(signature_bio: Box<BufferedReader<Cookie> + 's>,
reader: Box<'a + BufferedReader<()>>,
helper: H, t: time::Tm)
-> Result<Verifier<'a, H>>
where H: VerificationHelper
{
Verifier::from_buffered_reader(
Box::new(buffered_reader::Generic::with_cookie(
Transformer::new(signature_bio, reader)?,
None, Default::default())),
helper, t)
}
}
pub struct Decryptor<'a, H: VerificationHelper + DecryptionHelper> {
helper: H,
tpks: Vec<TPK>,
keys: HashMap<KeyID, (usize, usize)>,
oppr: Option<PacketParserResult<'a>>,
identity: Option<Fingerprint>,
sigs: Vec<Vec<Signature>>,
reserve: Option<Vec<u8>>,
time: time::Tm,
}
pub trait DecryptionHelper {
fn mapping(&self) -> bool {
false
}
fn inspect(&mut self, pp: &PacketParser) -> Result<()> {
let _ = pp;
Ok(())
}
fn decrypt<D>(&mut self, pkesks: &[PKESK], skesks: &[SKESK],
decrypt: D) -> Result<Option<Fingerprint>>
where D: FnMut(SymmetricAlgorithm, &SessionKey) -> Result<()>;
}
impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> {
pub fn from_reader<R, T>(reader: R, helper: H, t: T)
-> Result<Decryptor<'a, H>>
where R: io::Read + 'a, T: Into<Option<time::Tm>>
{
let t = t.into().unwrap_or_else(time::now_utc);
Decryptor::from_buffered_reader(
Box::new(buffered_reader::Generic::with_cookie(reader, None,
Default::default())),
helper, t)
}
pub fn from_file<P, T>(path: P, helper: H, t: T) -> Result<Decryptor<'a, H>>
where P: AsRef<Path>,
T: Into<Option<time::Tm>>
{
let t = t.into().unwrap_or_else(time::now_utc);
Decryptor::from_buffered_reader(
Box::new(buffered_reader::File::with_cookie(path,
Default::default())?),
helper, t)
}
pub fn from_bytes<T>(bytes: &'a [u8], helper: H, t: T)
-> Result<Decryptor<'a, H>>
where T: Into<Option<time::Tm>>
{
let t = t.into().unwrap_or_else(time::now_utc);
Decryptor::from_buffered_reader(
Box::new(buffered_reader::Memory::with_cookie(bytes,
Default::default())),
helper, t)
}
pub fn helper_ref(&self) -> &H {
&self.helper
}
pub fn helper_mut(&mut self) -> &mut H {
&mut self.helper
}
pub fn into_helper(self) -> H {
self.helper
}
pub fn message_processed(&self) -> bool {
self.oppr.is_none()
}
pub(crate) fn from_buffered_reader(bio: Box<BufferedReader<Cookie> + 'a>,
helper: H, t: time::Tm)
-> Result<Decryptor<'a, H>>
{
tracer!(TRACE, "Decryptor::from_buffered_reader", 0);
let mut ppr = PacketParserBuilder::from_buffered_reader(bio)?
.map(helper.mapping()).finalize()?;
let mut v = Decryptor {
helper: helper,
tpks: Vec::new(),
keys: HashMap::new(),
oppr: None,
identity: None,
sigs: Vec::new(),
reserve: None,
time: t,
};
let mut issuers = Vec::new();
let mut sigs = Vec::new();
let mut pkesks: Vec<packet::PKESK> = Vec::new();
let mut skesks: Vec<packet::SKESK> = Vec::new();
let mut saw_content = false;
while let PacketParserResult::Some(mut pp) = ppr {
v.helper.inspect(&pp)?;
if ! pp.possible_message() {
t!("Malformed message");
return Err(Error::MalformedMessage(
"Malformed OpenPGP message".into()).into());
}
match pp.packet {
Packet::SEIP(_) | Packet::AED(_) => {
saw_content = true;
v.identity =
v.helper.decrypt(&pkesks[..], &skesks[..],
|algo, secret| pp.decrypt(algo, secret)
)?;
if ! pp.decrypted() {
return Err(
Error::InvalidSessionKey("No session key".into())
.into());
}
},
Packet::OnePassSig(ref ops) =>
issuers.push(ops.issuer().clone()),
Packet::Literal(_) => {
v.tpks = v.helper.get_public_keys(&issuers)?;
for (i, tpk) in v.tpks.iter().enumerate() {
let can_sign = |key: &Key, sig: Option<&Signature>| -> bool {
if let Some(sig) = sig {
sig.key_flags().can_sign()
&& sig.signature_alive_at(t)
&& sig.key_alive_at(key, t)
} else {
false
}
};
if can_sign(tpk.primary(),
tpk.primary_key_signature()) {
v.keys.insert(tpk.keyid(), (i, 0));
}
for (j, skb) in tpk.subkeys().enumerate() {
let key = skb.subkey();
if can_sign(key, skb.binding_signature()) {
v.keys.insert(key.keyid(), (i, j + 1));
}
}
}
v.oppr = Some(PacketParserResult::Some(pp));
v.finish_maybe()?;
for sig in sigs.into_iter() {
v.push_sig(Packet::Signature(sig))?;
}
return Ok(v);
},
Packet::MDC(ref mdc) => if ! mdc.valid() {
return Err(Error::ManipulatedMessage.into());
},
_ => (),
}
let (p, ppr_tmp) = pp.recurse()?;
match p {
Packet::PKESK(pkesk) => pkesks.push(pkesk),
Packet::SKESK(skesk) => skesks.push(skesk),
Packet::Signature(sig) => {
if saw_content {
v.push_sig(Packet::Signature(sig))?;
} else {
if let Some(issuer) = sig.get_issuer() {
issuers.push(issuer);
} else {
issuers.push(KeyID::wildcard());
}
sigs.push(sig);
}
}
_ => (),
}
ppr = ppr_tmp;
}
Err(Error::MalformedMessage(
"Malformed OpenPGP message".into()).into())
}
fn push_sig(&mut self, p: Packet) -> Result<()> {
match p {
Packet::Signature(sig) => {
if self.sigs.is_empty() {
self.sigs.push(Vec::new());
}
if let Some(current_level) = self.sigs.iter().last()
.expect("sigs is never empty")
.get(0).map(|r| r.level())
{
if current_level != sig.level() {
self.sigs.push(Vec::new());
}
}
self.sigs.iter_mut().last()
.expect("sigs is never empty").push(sig);
},
_ => (),
}
Ok(())
}
fn finish_maybe(&mut self) -> Result<()> {
if let Some(PacketParserResult::Some(mut pp)) = self.oppr.take() {
let data_len = pp.data(BUFFER_SIZE + 1)?.len();
if data_len <= BUFFER_SIZE {
self.reserve = Some(pp.steal_eof()?);
let mut ppr = PacketParserResult::Some(pp);
let mut first = true;
while let PacketParserResult::Some(mut pp) = ppr {
if first {
assert_eq!(pp.packet.tag(), packet::Tag::Literal);
first = false;
} else {
self.helper.inspect(&pp)?;
}
if ! pp.possible_message() {
return Err(Error::MalformedMessage(
"Malformed OpenPGP message".into()).into());
}
match pp.packet {
Packet::MDC(ref mdc) => if ! mdc.valid() {
return Err(Error::ManipulatedMessage.into());
}
_ => (),
}
let (p, ppr_tmp) = pp.recurse()?;
self.push_sig(p)?;
ppr = ppr_tmp;
}
self.verify_signatures()
} else {
self.oppr = Some(PacketParserResult::Some(pp));
Ok(())
}
} else {
panic!("No ppr.");
}
}
fn verify_signatures(&mut self) -> Result<()> {
let mut results = Vec::new();
for sigs in ::std::mem::replace(&mut self.sigs, Vec::new())
.into_iter().rev()
{
results.push(Vec::new());
for sig in sigs.into_iter() {
results.iter_mut().last().expect("never empty").push(
if let Some(issuer) = sig.get_issuer() {
if let Some((i, j)) = self.keys.get(&issuer) {
let tpk = &self.tpks[*i];
let (binding, revocation, key)
= tpk.keys_all().nth(*j).unwrap();
if sig.verify(key).unwrap_or(false) &&
sig.signature_alive_at(self.time)
{
if let Some(identity) =
self.identity.as_ref()
{
let ir = sig.intended_recipients();
if !ir.is_empty()
&& !ir.contains(identity)
{
VerificationResult::BadChecksum
(sig)
} else {
VerificationResult::GoodChecksum
(sig, tpk, key, binding,
revocation)
}
} else {
VerificationResult::GoodChecksum
(sig, tpk, key, binding,
revocation)
}
} else {
VerificationResult::BadChecksum(sig)
}
} else {
VerificationResult::MissingKey(sig)
}
} else {
VerificationResult::BadChecksum(sig)
}
)
}
}
self.helper.check(results)
}
fn read_helper(&mut self, buf: &mut [u8]) -> Result<usize> {
if buf.len() == 0 {
return Ok(0);
}
if let Some(ref mut reserve) = self.reserve {
assert!(self.oppr.is_none());
let n = cmp::min(buf.len(), reserve.len());
&mut buf[..n].copy_from_slice(&reserve[..n]);
reserve.drain(..n);
return Ok(n);
}
if let Some(PacketParserResult::Some(mut pp)) = self.oppr.take() {
let data_len = pp.data(BUFFER_SIZE + buf.len())?.len();
if data_len <= BUFFER_SIZE {
self.oppr = Some(PacketParserResult::Some(pp));
self.finish_maybe()?;
self.read_helper(buf)
} else {
let n = cmp::min(buf.len(), data_len - BUFFER_SIZE);
let buf = &mut buf[..n];
let result = pp.read(buf);
self.oppr = Some(PacketParserResult::Some(pp));
Ok(result?)
}
} else {
panic!("No ppr.");
}
}
}
impl<'a, H: VerificationHelper + DecryptionHelper> io::Read for Decryptor<'a, H>
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self.read_helper(buf) {
Ok(n) => Ok(n),
Err(e) => match e.downcast::<io::Error>() {
Ok(e) => Err(e),
Err(e) => Err(io::Error::new(io::ErrorKind::Other,
e.compat())),
},
}
}
}
#[cfg(test)]
mod test {
use failure;
use std::fs::File;
use std::path::PathBuf;
use super::*;
use parse::Parse;
fn path_to(artifact: &str) -> PathBuf {
[env!("CARGO_MANIFEST_DIR"), "tests", "data", artifact]
.iter().collect()
}
#[derive(Debug, PartialEq)]
struct VHelper {
good: usize,
unknown: usize,
bad: usize,
error: usize,
keys: Vec<TPK>,
}
impl Default for VHelper {
fn default() -> Self {
VHelper {
good: 0,
unknown: 0,
bad: 0,
error: 0,
keys: Vec::default(),
}
}
}
impl VHelper {
fn new(good: usize, unknown: usize, bad: usize, error: usize, keys: Vec<TPK>) -> Self {
VHelper {
good: good,
unknown: unknown,
bad: bad,
error: error,
keys: keys,
}
}
}
impl VerificationHelper for VHelper {
fn get_public_keys(&mut self, _ids: &[KeyID]) -> Result<Vec<TPK>> {
Ok(self.keys.clone())
}
fn check(&mut self, sigs: Vec<Vec<VerificationResult>>) -> Result<()> {
use self::VerificationResult::*;
for level in sigs {
for result in level {
match result {
GoodChecksum(..) => self.good += 1,
MissingKey(_) => self.unknown += 1,
BadChecksum(_) => self.bad += 1,
}
}
}
if self.good > 0 && self.bad == 0 {
Ok(())
} else {
Err(failure::err_msg("Verification failed"))
}
}
}
impl DecryptionHelper for VHelper {
fn decrypt<D>(&mut self, _: &[PKESK], _: &[SKESK], _: D)
-> Result<Option<Fingerprint>>
where D: FnMut(SymmetricAlgorithm, &SessionKey) -> Result<()>
{
unreachable!();
}
}
#[test]
fn verifier() {
let keys = [
"neal.pgp",
"emmelie-dorothea-dina-samantha-awina-ed25519.pgp"
].iter()
.map(|f| TPK::from_file(
path_to(&format!("keys/{}", f))).unwrap())
.collect::<Vec<_>>();
let tests = &[
("messages/signed-1.gpg", VHelper::new(1, 0, 0, 0, keys.clone())),
("messages/signed-1-sha256-testy.gpg", VHelper::new(0, 1, 0, 0, keys.clone())),
("messages/signed-1-notarized-by-ed25519.pgp", VHelper::new(2, 0, 0, 0, keys.clone())),
("keys/neal.pgp", VHelper::new(0, 0, 0, 1, keys.clone())),
];
let mut reference = Vec::new();
File::open(path_to("messages/a-cypherpunks-manifesto.txt"))
.unwrap()
.read_to_end(&mut reference)
.unwrap();
for (f, r) in tests {
let mut h = VHelper::new(0, 0, 0, 0, keys.clone());
let mut v =
match Verifier::from_file(path_to(f), h, ::frozen_time()) {
Ok(v) => v,
Err(e) => if r.error > 0 || r.unknown > 0 {
continue;
} else {
panic!("{}: {}", f, e);
},
};
assert!(v.message_processed());
assert_eq!(v.helper_ref(), r);
if v.helper_ref().error > 0 {
continue;
}
let mut content = Vec::new();
v.read_to_end(&mut content).unwrap();
assert_eq!(reference.len(), content.len());
assert_eq!(reference, content);
let mut h = VHelper::new(0, 0, 0, 0, keys.clone());
let mut v =
match Decryptor::from_file(path_to(f), h, ::frozen_time()) {
Ok(v) => v,
Err(e) => if r.error > 0 || r.unknown > 0 {
continue;
} else {
panic!(e);
},
};
assert!(v.message_processed());
assert_eq!(v.helper_ref(), r);
if v.helper_ref().error > 0 {
continue;
}
let mut content = Vec::new();
v.read_to_end(&mut content).unwrap();
assert_eq!(reference.len(), content.len());
assert_eq!(reference, content);
}
}
#[test]
fn verifier_levels() {
struct VHelper(());
impl VerificationHelper for VHelper {
fn get_public_keys(&mut self, _ids: &[KeyID]) -> Result<Vec<TPK>> {
Ok(Vec::new())
}
fn check(&mut self, sigs: Vec<Vec<VerificationResult>>)
-> Result<()> {
assert_eq!(sigs.len(), 2);
assert_eq!(sigs[0].len(), 1);
assert_eq!(sigs[1].len(), 1);
if let VerificationResult::MissingKey(ref sig) = sigs[1][0] {
assert_eq!(
&sig.issuer_fingerprint().unwrap().to_string(),
"C03F A641 1B03 AE12 5764 6118 7223 B566 78E0 2528");
} else {
unreachable!()
}
if let VerificationResult::MissingKey(ref sig) = sigs[0][0] {
assert_eq!(
&sig.issuer_fingerprint().unwrap().to_string(),
"8E8C 33FA 4626 3379 76D9 7978 069C 0C34 8DD8 2C19");
} else {
unreachable!()
}
Ok(())
}
}
impl DecryptionHelper for VHelper {
fn decrypt<D>(&mut self, _: &[PKESK], _: &[SKESK], _: D)
-> Result<Option<Fingerprint>>
where D: FnMut(SymmetricAlgorithm, &SessionKey) -> Result<()>
{
unreachable!();
}
}
let v = Verifier::from_file(
path_to("messages/signed-1-notarized-by-ed25519.pgp"),
VHelper(()), ::frozen_time()).unwrap();
assert!(v.message_processed());
let v = Decryptor::from_file(
path_to("messages/signed-1-notarized-by-ed25519.pgp"),
VHelper(()), ::frozen_time()).unwrap();
assert!(v.message_processed());
}
#[test]
fn detached_verifier() {
let keys = [
"emmelie-dorothea-dina-samantha-awina-ed25519.pgp"
].iter()
.map(|f| TPK::from_file(
path_to(&format!("keys/{}", f))).unwrap())
.collect::<Vec<_>>();
let mut reference = Vec::new();
File::open(path_to("messages/a-cypherpunks-manifesto.txt"))
.unwrap()
.read_to_end(&mut reference)
.unwrap();
let h = VHelper::new(0, 0, 0, 0, keys.clone());
let mut v = DetachedVerifier::from_file(
path_to("messages/a-cypherpunks-manifesto.txt.ed25519.sig"),
path_to("messages/a-cypherpunks-manifesto.txt"),
h, ::frozen_time()).unwrap();
assert!(v.message_processed());
let mut content = Vec::new();
v.read_to_end(&mut content).unwrap();
assert_eq!(reference.len(), content.len());
assert_eq!(reference, content);
let h = v.into_helper();
assert_eq!(h.good, 1);
assert_eq!(h.bad, 0);
let h = VHelper::new(0, 0, 0, 0, keys.clone());
let mut v = DetachedVerifier::from_reader(
File::open(
path_to("messages/a-cypherpunks-manifesto.txt.ed25519.sig"))
.unwrap(),
File::open(
path_to("messages/a-cypherpunks-manifesto.txt"))
.unwrap(),
h, ::frozen_time()).unwrap();
assert!(v.message_processed());
let mut content = Vec::new();
v.read_to_end(&mut content).unwrap();
assert_eq!(reference.len(), content.len());
assert_eq!(reference, content);
}
#[test]
fn verify_long_message() {
use constants::DataFormat;
use tpk::{TPKBuilder, CipherSuite};
use serialize::stream::{LiteralWriter, Signer, Message};
use packet::key::SecretKey;
use crypto::KeyPair;
use std::io::Write;
let (tpk, _) = TPKBuilder::default()
.set_cipher_suite(CipherSuite::Cv25519)
.add_signing_subkey()
.generate().unwrap();
let mut buf = vec![];
{
let key = tpk.keys_all().signing_capable().nth(0).unwrap().2;
let sec = match key.secret() {
Some(SecretKey::Unencrypted { ref mpis }) => mpis,
_ => unreachable!(),
};
let mut keypair = KeyPair::new(key.clone(), sec.clone()).unwrap();
let m = Message::new(&mut buf);
let signer = Signer::new(m, vec![&mut keypair], None).unwrap();
let mut ls = LiteralWriter::new(signer, DataFormat::Binary, None, None).unwrap();
ls.write_all(&mut vec![42u8; 30 * 1024 * 1024]).unwrap();
ls.finalize().unwrap();
}
let h = VHelper::new(0, 0, 0, 0, vec![tpk.clone()]);
let mut v = Verifier::from_bytes(&buf, h, None).unwrap();
assert!(!v.message_processed());
assert!(v.helper_ref().good == 0);
assert!(v.helper_ref().bad == 0);
assert!(v.helper_ref().unknown == 0);
assert!(v.helper_ref().error == 0);
let mut message = Vec::new();
v.read_to_end(&mut message).unwrap();
assert!(v.message_processed());
assert_eq!(30 * 1024 * 1024, message.len());
assert!(message.iter().all(|&b| b == 42));
assert!(v.helper_ref().good == 1);
assert!(v.helper_ref().bad == 0);
assert!(v.helper_ref().unknown == 0);
assert!(v.helper_ref().error == 0);
let h = VHelper::new(0, 0, 1, 0,
vec![tpk.clone()]);
let mut v = Verifier::from_bytes(&buf, h, None).unwrap();
assert!(!v.message_processed());
assert!(v.helper_ref().good == 0);
assert!(v.helper_ref().bad == 1);
assert!(v.helper_ref().unknown == 0);
assert!(v.helper_ref().error == 0);
let mut message = Vec::new();
let r = v.read_to_end(&mut message);
assert!(r.is_err());
assert!(v.message_processed());
assert!(message.len() > 0);
assert!(message.len() <= 5 * 1024 * 1024);
assert!(message.iter().all(|&b| b == 42));
assert!(v.helper_ref().good == 1);
assert!(v.helper_ref().bad == 1);
assert!(v.helper_ref().unknown == 0);
assert!(v.helper_ref().error == 0);
let h = VHelper::new(0, 0, 0, 0, vec![tpk.clone()]);
let mut v = Decryptor::from_bytes(&buf, h, None).unwrap();
assert!(!v.message_processed());
assert!(v.helper_ref().good == 0);
assert!(v.helper_ref().bad == 0);
assert!(v.helper_ref().unknown == 0);
assert!(v.helper_ref().error == 0);
let mut message = Vec::new();
v.read_to_end(&mut message).unwrap();
assert!(v.message_processed());
assert_eq!(30 * 1024 * 1024, message.len());
assert!(message.iter().all(|&b| b == 42));
assert!(v.helper_ref().good == 1);
assert!(v.helper_ref().bad == 0);
assert!(v.helper_ref().unknown == 0);
assert!(v.helper_ref().error == 0);
let h = VHelper::new(0, 0, 1, 0,
vec![tpk.clone()]);
let mut v = Decryptor::from_bytes(&buf, h, None).unwrap();
assert!(!v.message_processed());
assert!(v.helper_ref().good == 0);
assert!(v.helper_ref().bad == 1);
assert!(v.helper_ref().unknown == 0);
assert!(v.helper_ref().error == 0);
let mut message = Vec::new();
let r = v.read_to_end(&mut message);
assert!(r.is_err());
assert!(v.message_processed());
assert!(message.len() > 0);
assert!(message.len() <= 5 * 1024 * 1024);
assert!(message.iter().all(|&b| b == 42));
assert!(v.helper_ref().good == 1);
assert!(v.helper_ref().bad == 1);
assert!(v.helper_ref().unknown == 0);
assert!(v.helper_ref().error == 0);
}
}