mod manual;
mod meta_data;
mod result;
mod setup;
mod suite;
mod tally;
mod verifications;
use std::fmt::Display;
pub use self::{
manual::*,
meta_data::*,
result::{VerficationsWithErrorAndFailures, VerificationEvent, VerificationResult},
setup::get_verifications as get_verifications_setup,
suite::VerificationSuite,
tally::get_verifications as get_verifications_tally,
};
use crate::{
config::{VerifierConfig, VerifierConfigError},
data_structures::DataStructureError,
direct_trust::{DirectTrustError, VerifiySignatureTrait},
file_structure::{FileStructureError, VerificationDirectoryTrait},
};
use thiserror::Error;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, strum::EnumString, strum::AsRefStr)]
#[strum(serialize_all = "lowercase")]
pub enum VerificationCategory {
Authenticity,
Consistency,
Completness,
Integrity,
Evidence,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, strum::EnumString, strum::AsRefStr)]
#[strum(serialize_all = "lowercase")]
pub enum VerificationStatus {
#[strum(serialize = "Not started")]
NotStarted,
#[strum(serialize = "Running")]
Running,
#[strum(serialize = "Successful")]
FinishedSuccessfully,
#[strum(serialize = "Failures")]
FinishedWithFailures,
#[strum(serialize = "Errors")]
FinishedWithErrors,
#[strum(serialize = "Failures and Errors")]
FinishedWithFailuresAndErrors,
}
impl VerificationStatus {
pub fn calculate_finished(has_errors: bool, has_failures: bool) -> Self {
match has_errors {
true => match has_failures {
true => Self::FinishedWithFailuresAndErrors,
false => Self::FinishedWithErrors,
},
false => match has_failures {
true => Self::FinishedWithFailures,
false => Self::FinishedSuccessfully,
},
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, strum::EnumString, strum::AsRefStr)]
#[strum(serialize_all = "lowercase")]
pub enum VerificationPeriod {
Setup,
Tally,
}
impl Display for VerificationPeriod {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
VerificationPeriod::Setup => "Setup",
VerificationPeriod::Tally => "Tally",
}
)
}
}
#[derive(Error, Debug)]
#[error(transparent)]
pub struct VerificationError(#[from] VerificationErrorImpl);
#[derive(Error, Debug)]
enum VerificationErrorImpl {
#[error("Error loading metadata")]
LoadMetadata { source: serde_json::Error },
#[error("Error loading metadata for period {period}")]
LoadMetadataPeriod {
period: VerificationPeriod,
source: Box<VerificationError>,
},
#[error("Error getting the keystore creating the manual verifications for all periods")]
KeystoreNewAll { source: VerifierConfigError },
#[error(
"Error getting the fingerprints of the certificate creating the manual verifications for all periods"
)]
FingerprintsNewAll { source: DirectTrustError },
#[error(
"Error getting the election event context creating the manual verifications for all periods"
)]
EEContextNewAll { source: Box<FileStructureError> },
#[error("Error getting the election event context creating the manual verifications for tally")]
EEContextNewTally { source: Box<FileStructureError> },
#[error("Ballot box {bb_id} not found in the directories")]
BBNotFoundNewTally { bb_id: String },
#[error(
"Error reading {bb_id}/tally_component_votes_payload creating the manual verifications for tally"
)]
BBVotesNewTally {
bb_id: String,
source: Box<FileStructureError>,
},
#[error(
"Error creating the manual verifications for all period creating the manual verifications for tally"
)]
NewAllInNewTally { source: Box<VerificationError> },
#[error(
"Error creating the manual verifications for all period creating the manual verifications for setup"
)]
NewAllInNewSetup { source: Box<VerificationError> },
#[error("Error collecting metadata creating the manual verifications")]
MetadataNew { source: Box<VerificationError> },
#[error("Error creating manual verifications for {period} creating the manual verifications")]
NewManual {
period: VerificationPeriod,
source: Box<VerificationError>,
},
#[error(
"Error creating the inputs for the manual verifications from the election event context (creating verifications for all periods)"
)]
VerifInputsNewAll { source: DataStructureError },
#[error(
"Metadata for verification {id} not found in the list of metadata (creating the verification"
)]
MetadataNotFound { id: String },
#[error(
"name {name} for verification id {id} doesn't match with give name {input_name} (creating the verification)"
)]
NameMismatch {
name: String,
id: String,
input_name: String,
},
#[error("Error creating verification {name}")]
GetVerification {
name: &'static str,
source: Box<VerificationError>,
},
#[error("Error creating verifications for categroy {category}")]
GetCategory {
category: &'static str,
source: Box<VerificationError>,
},
#[error("Error creating verifications for period {period}")]
GetPeriod {
period: VerificationPeriod,
source: Box<VerificationError>,
},
#[error("Error calculating the fingerprint of ech-0222 file")]
ECH0222 { source: Box<FileStructureError> },
}
impl VerificationPeriod {
pub fn is_setup(&self) -> bool {
self == &VerificationPeriod::Setup
}
pub fn is_tally(&self) -> bool {
self == &VerificationPeriod::Tally
}
}
#[allow(dead_code)]
pub(super) fn verification_unimplemented<D: VerificationDirectoryTrait>(
_dir: &D,
_config: &'static VerifierConfig,
result: &mut VerificationResult,
) {
result.push(VerificationEvent::new_error(
"Verification is not implemented",
));
}
fn verify_signature_for_object<'a, T>(
obj: &'a T,
config: &'static VerifierConfig,
) -> VerificationResult
where
T: VerifiySignatureTrait<'a>,
{
let mut result = VerificationResult::new();
let ks = match config.keystore() {
Ok(ks) => ks,
Err(e) => {
result.push(
VerificationEvent::new_error_from_error(&e).add_context("Cannot read keystore"),
);
return result;
}
};
let res = obj.verify_signatures(&ks);
for (i, r) in res.iter().enumerate() {
match r {
Ok(t) => {
if !t {
result.push(VerificationEvent::new_failure("Wrong signature"))
}
}
Err(e) => {
result.push(
VerificationEvent::new_failure(e).add_context(format!("at position {i}")),
);
}
}
}
result
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_calculate_finished() {
assert_eq!(
VerificationStatus::calculate_finished(false, false),
VerificationStatus::FinishedSuccessfully
);
assert_eq!(
VerificationStatus::calculate_finished(true, false),
VerificationStatus::FinishedWithErrors
);
assert_eq!(
VerificationStatus::calculate_finished(false, true),
VerificationStatus::FinishedWithFailures
);
assert_eq!(
VerificationStatus::calculate_finished(true, true),
VerificationStatus::FinishedWithFailuresAndErrors
);
}
}