diff --git a/Cargo.toml b/Cargo.toml index 7bf02a2..41d11bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ log4rs = "1.3.0" sequoia-cert-store = "0.7.1" sequoia-directories = "0.1.0" sequoia-openpgp = "2.1.0" +sequoia-wot = "0.15.0" serde = "1.0.228" serde_derive = "1.0.228" thiserror = "2.0.17" diff --git a/src/crypto.rs b/src/crypto.rs index ef55fb6..2c84748 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -4,12 +4,18 @@ // cryptographic functions // +use std::sync::Arc; + use anyhow; use sequoia_openpgp::parse::Parse; use sequoia_openpgp::{Fingerprint, Cert}; use sequoia_openpgp::cert::raw::RawCertParser; -use sequoia_cert_store::CertStore; +use sequoia_cert_store::{Store, CertStore, LazyCert}; +use sequoia_wot::{self as wot}; +use wot::store::Store as _; + use crate::types::errors::HuskError; +use crate::types::husk_context::HuskContext; pub fn get_local_trust_root(cert_store: &CertStore) -> anyhow::Result { @@ -45,3 +51,34 @@ pub fn get_local_trust_root(cert_store: &CertStore) -> anyhow::Result { } } + +pub fn get_certificates<'hc>(context: &HuskContext<'hc>, email: &str) + -> Vec>> { + + let cert_store = &context.cert_store; + let trust_roots = vec![(context.local_trust_root.fingerprint(), wot::FULLY_TRUSTED)]; + let wot_store = wot::store::CertStore::from_store(cert_store, &context.policy, None); + let nb = wot::NetworkBuilder::rooted(&wot_store, &*trust_roots); + let n = nb.build(); + + let bindings: Vec<_> = n.lookup_synopses_by_email(email) + .into_iter() + .map(|(fp, userid)| (fp, Some(userid))) + .collect(); + + let mut result = vec![]; + for (fpr, some_userid) in bindings { + if let Some(userid) = some_userid { + let paths = n.authenticate(userid, &fpr, wot::FULLY_TRUSTED); + if paths.len() > 0 { + log::debug!("authenticated!!!"); + for (path, _) in paths.iter() { + if let Ok(cert) = cert_store.lookup_by_cert_fpr(&path.target().fingerprint()) { + result.push(cert); + } + } + } + } + } + result +} diff --git a/src/types/husk_context.rs b/src/types/husk_context.rs index dab8da5..234d524 100644 --- a/src/types/husk_context.rs +++ b/src/types/husk_context.rs @@ -51,7 +51,10 @@ impl<'hc> HuskContext<'hc> { } pub fn add_recipient(&mut self, rcpt: String) -> anyhow::Result<()> { - self.mail.add_recipient(rcpt) + + let certs = crypto::get_certificates(&self, rcpt.as_str()); + + self.mail.add_recipient(rcpt, certs) } } diff --git a/src/types/mail_context.rs b/src/types/mail_context.rs index f60c8ec..877f55a 100644 --- a/src/types/mail_context.rs +++ b/src/types/mail_context.rs @@ -4,34 +4,20 @@ // Mail Context // -use anyhow; +use std::sync::Arc; +use sequoia_cert_store::LazyCert; -use sequoia_openpgp::cert::ValidCert; +use crate::types::recipient::Recipient; -#[derive(Debug, Clone)] -pub struct Recipient<'r> { - pub email: String, - pub cert: Option>, -} - -impl From for Recipient<'_> { - fn from(email: String) -> Self { - Recipient { - email: email, - cert: None - } - } -} - -pub struct MailContext<'c> { +pub struct MailContext<'mc> { pub sender: Option, - pub recipients: Vec>, + pub recipients: Vec>, // header // body // body size } -impl MailContext<'_> { +impl<'mc> MailContext<'mc> { pub fn new() -> Self { MailContext { @@ -44,8 +30,9 @@ impl MailContext<'_> { self.sender = Some(sender); } - pub fn add_recipient(&mut self, rcpt: String) -> anyhow::Result<()> { - let recipient: Recipient = rcpt.into(); + pub fn add_recipient(&mut self, rcpt: String, certs: Vec>>) -> anyhow::Result<()> { + let mut recipient: Recipient = rcpt.into(); + recipient.certs = certs; self.recipients.push(recipient); diff --git a/src/types/mod.rs b/src/types/mod.rs index 01c14ea..4ba6c8e 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -1,3 +1,4 @@ pub mod husk_context; pub mod mail_context; pub mod errors; +pub mod recipient; diff --git a/src/types/recipient.rs b/src/types/recipient.rs new file mode 100644 index 0000000..0d93a03 --- /dev/null +++ b/src/types/recipient.rs @@ -0,0 +1,39 @@ +// +// Husk milter +// +// Recipient +// + +use anyhow; +use std::sync::Arc; +use std::ffi::CString; +use sequoia_cert_store::LazyCert; + +#[derive(Debug, Clone)] +pub struct Recipient<'r> { + pub email: String, + pub certs: Vec>> +} + +impl From for Recipient<'_> { + fn from(email: String) -> Self { + Recipient { + email: email, + certs: Vec::new() + } + } +} + +impl TryFrom for Recipient<'_> { + + type Error=anyhow::Error; + + fn try_from(value: CString) -> Result { + match value.into_string() { + Ok(s) => Ok(s.into()), + Err(e) => Err(e.into()), + } + } +} + +