Add lookup for email addresses in the updater

- Only considering the fingerprint of a certificate for online querying
  of updates leaves out WKD and DANE as sources. Add the email addresses
  of a certificate to the update process.
This commit is contained in:
Malte Meiboom
2026-08-12 11:35:58 +02:00
parent 04322f9cd9
commit f9df6a5daa
5 changed files with 60 additions and 14 deletions
+2 -2
View File
@@ -46,8 +46,8 @@ keyservers = [ "hkp://example.com" ]
#
# wait_min and wait_max specify the range for that randomness.
# defaults:
# min_wait = 5
# max_wait = 3600
# wait_min = 5
# wait_max = 3600
wait_min = 1
wait_max = 2
+10 -2
View File
@@ -22,6 +22,7 @@ use sequoia_openpgp::packet::prelude::SignatureBuilder;
use sequoia_openpgp::parse::{PacketParser, PacketParserResult, Parse};
use sequoia_openpgp::policy::StandardPolicy;
use sequoia_openpgp::serialize::stream::{Message, Armorer, Encryptor, Signer, LiteralWriter};
use sequoia_openpgp::serialize::stream::padding::Padder;
use sequoia_openpgp::{Fingerprint, Cert, Packet};
use sequoia_openpgp::types::SignatureType;
use sequoia_cert_store::{Store, CertStore, LazyCert, StoreUpdate};
@@ -210,8 +211,8 @@ async fn query_online_sources<'hc>(context: &HuskContext<'hc>, query: OnlineQuer
Ok(certs) => {
partial_result = collect_certs(certs, q, &p);
}
Err(e) => {
log::debug!("Error: {}", e.to_string());
Err(err) => {
log::debug!("Error: {} {}", e, err.to_string());
}
}
/*
@@ -482,9 +483,14 @@ pub fn is_encrypted(body: &Bytes) -> bool {
pub fn encrypt(context: &HuskContext<'_>, body: &[u8], recipients: &Vec<Recipient>)
-> anyhow::Result<Bytes> {
log::debug!("encrypt for {}", recipients.iter()
.map(|r| r.email.clone())
.collect::<Vec<String>>()
.join(", "));
let mut keys = Vec::new();
for rcpt in recipients {
log::debug!("Check recipient {}", rcpt.email);
if rcpt.can_encrypt() {
for cert in &rcpt.certs {
cert.with_policy(&context.policy, None)?
@@ -504,6 +510,7 @@ pub fn encrypt(context: &HuskContext<'_>, body: &[u8], recipients: &Vec<Recipien
let message = Message::new(&mut sink);
let message = Armorer::new(message).build()?;
let mut message = Encryptor::for_recipients(message, keys).build()?;
message = Padder::new(message).build()?;
if let Some(key) = &context.signing_key {
log::debug!("use signing key {}", key.fingerprint());
message = Signer::new(message, key.clone())?.build()?;
@@ -521,6 +528,7 @@ pub fn encrypt(context: &HuskContext<'_>, body: &[u8], recipients: &Vec<Recipien
Ok(Bytes::from(sink))
} else {
log::debug!("not keys at all");
Err(HuskError::NoEncryptionKeys.into())
}
}
+3 -3
View File
@@ -30,11 +30,11 @@ impl From<Option<String>> for TorConnectorType {
fn from(value: Option<String>) -> Self {
match value {
Some(v) => {
if v.to_ascii_lowercase() == "arti" {
if v.eq_ignore_ascii_case("arti") {
TorConnectorType::Arti
} else {
if v.starts_with("socks5://") {
TorConnectorType::SocksProxy(v[9..].to_string())
if let Some(url) = v.strip_prefix("socks5://") {
TorConnectorType::SocksProxy(url.to_string())
} else {
TorConnectorType::Errornous
}
+36 -4
View File
@@ -4,6 +4,7 @@ use std::path::Path;
use std::sync::Arc;
use sequoia_cert_store::LazyCert;
use sequoia_cert_store::Store;
use sequoia_cert_store::StoreUpdate;
use sequoia_cert_store::store::MergePublicCollectStats;
use tokio::time::sleep;
@@ -40,7 +41,7 @@ impl Updater {
let mut updater_state = UpdaterState::thaw(state_path)
.await
.map_err(|e| { stay = false; e })?;
.inspect_err(|_| { stay = false; })?;
let mut context = HuskContext::without_signkey(&c)?;
context.for_updater(&c);
updater_state.refresh(&context);
@@ -48,9 +49,40 @@ impl Updater {
if let Some(fpr) = updater_state.next() {
log::debug!("try to update {}", fpr.to_hex());
// get local cert from cert store to get the user emails
let mut emails = Vec::new();
if let Ok(local_certs) = context.cert_store.lookup_by_cert(&fpr.clone().into()) {
local_certs.iter()
.map(|c| c.with_policy(&context.policy, None))
.filter_map(|c| c.ok())
.filter(|c|
c.keys()
.supported()
.alive()
.revoked(false)
.for_transport_encryption()
.count() > 0)
.for_each(|c|
c.userids()
.map(|u| u.userid().email())
.filter_map(|u| if let Ok(e) = u { e } else { None })
.for_each(|e| emails.push(e.to_string()))
);
}
log::debug!("with emails: {:?}", emails);
let stats = MergePublicCollectStats::new();
let certs = crypto::lookup_fingerprint(&context, fpr.to_hex().as_str()).await?;
let mut certs = crypto::lookup_fingerprint(&context, fpr.to_hex().as_str()).await?;
for email in emails {
crypto::lookup_email(&context, email.as_str()).await?.iter()
.for_each(|c| {
if c.fingerprint() == fpr {
certs.push(c.clone());
}
});
}
if !certs.is_empty() {
for cert in certs {
let cert = Arc::new(LazyCert::from_cert(cert));
@@ -66,7 +98,7 @@ impl Updater {
}
UpdaterState::freeze(state_path, &updater_state)
.await
.map_err(|e| { stay = false; e })?;
.inspect_err(|_| { stay = false; })?;
} else {
// finished update round
let (processed, updated) = updater_state.summarize();
@@ -76,7 +108,7 @@ impl Updater {
// remove state from disk
UpdaterState::remove(state_path)
.await
.map_err(|e| { stay = false; e })?;
.inspect_err(|_| { stay = false; })?;
}
}
+9 -3
View File
@@ -98,7 +98,7 @@ impl CertState {
pub fn new(fpr: Fingerprint) -> Self {
Self {
fpr: fpr,
fpr,
processed: false,
updated: false,
retry_count: 0,
@@ -171,7 +171,7 @@ impl TryFrom<Vec<u8>> for UpdaterState {
impl fmt::Display for UpdaterState {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "{}", self.started.format(DATETIME_PATTERN))?;
for (_, cert) in &self.certs {
for cert in self.certs.values() {
write!(f, "{}", cert)?;
}
@@ -179,6 +179,12 @@ impl fmt::Display for UpdaterState {
}
}
impl Default for UpdaterState {
fn default() -> Self {
Self::new()
}
}
impl UpdaterState {
pub fn new() -> Self {
@@ -313,7 +319,7 @@ impl UpdaterState {
pub fn summarize(&self) -> (usize, usize) {
let mut processed = 0;
let mut updated = 0;
for (_, cert) in &self.certs {
for cert in self.certs.values() {
if cert.processed { processed += 1; }
if cert.updated { updated += 1; }
}