Don't create a provenence record when it already exists
- When importing a certificate downloaded from a known verifying keyserver, a WKD or DANE, we certify the User IDs that the server (probably) authenticated. - If we download the certificate again from the same source, don't create another certification. That's just redundant.
This commit is contained in:
parent
427487b76c
commit
ee96205df9
@ -16,13 +16,14 @@ use openpgp::types::{
|
||||
};
|
||||
use openpgp::cert::prelude::*;
|
||||
use openpgp::crypto;
|
||||
use openpgp::{Cert, KeyID, Result};
|
||||
use openpgp::{Cert, Fingerprint, KeyID, Result};
|
||||
use openpgp::packet::prelude::*;
|
||||
use openpgp::parse::{
|
||||
Parse,
|
||||
PacketParserResult,
|
||||
};
|
||||
use openpgp::parse::stream::*;
|
||||
use openpgp::policy::HashAlgoSecurity;
|
||||
use openpgp::serialize::stream::{
|
||||
Message, Signer, LiteralWriter, Encryptor, Recipient,
|
||||
Compressor,
|
||||
@ -258,6 +259,96 @@ fn get_certification_keys<C>(certs: &[C], p: &dyn Policy,
|
||||
options)
|
||||
}
|
||||
|
||||
/// Returns the active certification, if any, for the specified bindings.
|
||||
///
|
||||
/// The certificate is looked up in the certificate store.
|
||||
///
|
||||
/// Note: if `n` User IDs are provided, then the returned vector has
|
||||
/// `n` elements.
|
||||
fn active_certification(config: &Config,
|
||||
cert: &Fingerprint, userids: Vec<UserID>,
|
||||
issuer: &Key<openpgp::packet::key::PublicParts,
|
||||
openpgp::packet::key::UnspecifiedRole>)
|
||||
-> Vec<(UserID, Option<Signature>)>
|
||||
{
|
||||
// Look up the cert and find the certifications for the specified
|
||||
// User ID, if any.
|
||||
let lc = config.cert_store_or_else()
|
||||
.and_then(|cert_store| cert_store.lookup_by_cert_fpr(cert));
|
||||
let lc = match lc {
|
||||
Ok(lc) => lc,
|
||||
Err(_) => {
|
||||
return userids.into_iter().map(|userid| (userid, None)).collect();
|
||||
}
|
||||
};
|
||||
let cert = match lc.to_cert() {
|
||||
Ok(cert) => cert,
|
||||
Err(_) => {
|
||||
return userids.into_iter().map(|userid| (userid, None)).collect();
|
||||
}
|
||||
};
|
||||
|
||||
let issuer_kh = issuer.key_handle();
|
||||
|
||||
userids.into_iter().map(|userid| {
|
||||
let ua = match cert.userids()
|
||||
.filter(|ua| ua.userid() == &userid).next()
|
||||
{
|
||||
Some(ua) => ua,
|
||||
None => return (userid, None),
|
||||
};
|
||||
|
||||
// Get certifications that:
|
||||
//
|
||||
// - Have a creation time,
|
||||
// - Are not younger than the reference time,
|
||||
// - Are not expired,
|
||||
// - Alias the issuer, and
|
||||
// - Satisfy the policy.
|
||||
let mut certifications = ua.bundle().certifications()
|
||||
.iter()
|
||||
.filter(|sig| {
|
||||
if let Some(ct) = sig.signature_creation_time() {
|
||||
ct <= config.time
|
||||
&& sig.signature_validity_period()
|
||||
.map(|vp| {
|
||||
config.time < ct + vp
|
||||
})
|
||||
.unwrap_or(true)
|
||||
&& sig.get_issuers().iter().any(|i| i.aliases(&issuer_kh))
|
||||
&& config.policy.signature(
|
||||
sig, HashAlgoSecurity::CollisionResistance).is_ok()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.collect::<Vec<&Signature>>();
|
||||
|
||||
// Sort so the newest signature is first.
|
||||
certifications.sort_unstable_by(|a, b| {
|
||||
a.signature_creation_time().unwrap()
|
||||
.cmp(&b.signature_creation_time().unwrap())
|
||||
.reverse()
|
||||
.then(a.mpis().cmp(&b.mpis()))
|
||||
});
|
||||
|
||||
// Return the first valid signature, which is the most recent one
|
||||
// that is no younger than config.time.
|
||||
let pk = ua.cert().primary_key().key();
|
||||
let certification = certifications.into_iter()
|
||||
.filter_map(|sig| {
|
||||
let mut sig = sig.clone();
|
||||
if sig.verify_userid_binding(issuer, pk, &userid).is_ok() {
|
||||
Some(sig)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.next();
|
||||
(userid, certification)
|
||||
}).collect()
|
||||
}
|
||||
|
||||
// Returns the smallest valid certificate.
|
||||
//
|
||||
// Given a certificate, returns the smallest valid certificate that is
|
||||
|
@ -36,7 +36,10 @@ use cert_store::StoreUpdate;
|
||||
use cert_store::store::UserIDQueryParams;
|
||||
|
||||
use crate::{
|
||||
commands::get_certification_keys,
|
||||
commands::{
|
||||
active_certification,
|
||||
get_certification_keys,
|
||||
},
|
||||
Config,
|
||||
Model,
|
||||
open_or_stdin,
|
||||
@ -102,7 +105,8 @@ fn import_certs(config: &mut Config, certs: Vec<Cert>) -> Result<()> {
|
||||
///
|
||||
/// This does not import the certification or the certificate into
|
||||
/// the certificate store.
|
||||
fn certify(signer: &mut dyn Signer, cert: &Cert, userids: &[UserID],
|
||||
fn certify(config: &Config,
|
||||
signer: &mut dyn Signer, cert: &Cert, userids: &[UserID],
|
||||
creation_time: Option<SystemTime>, depth: u8, amount: usize)
|
||||
-> Result<Cert>
|
||||
{
|
||||
@ -118,8 +122,20 @@ fn certify(signer: &mut dyn Signer, cert: &Cert, userids: &[UserID],
|
||||
builder = builder.set_signature_creation_time(creation_time)?;
|
||||
}
|
||||
|
||||
let certifications = userids.iter()
|
||||
.map(|userid| {
|
||||
let certifications = active_certification(
|
||||
config, &cert.fingerprint(),
|
||||
userids.iter().cloned().collect(),
|
||||
signer.public())
|
||||
.into_iter()
|
||||
.map(|(userid, active_certification)| {
|
||||
if let Some(_) = active_certification {
|
||||
eprintln!("Provenance information for {}, {:?} \
|
||||
exists and is current, not updating it",
|
||||
cert.fingerprint(),
|
||||
String::from_utf8_lossy(userid.value()));
|
||||
return vec![];
|
||||
}
|
||||
|
||||
match builder.clone().sign_userid_binding(
|
||||
signer,
|
||||
cert.primary_key().key(),
|
||||
@ -193,7 +209,7 @@ fn get_ca(config: &mut Config,
|
||||
assert_eq!(signers.len(), 1);
|
||||
let mut signer = signers.into_iter().next().unwrap();
|
||||
|
||||
match certify(&mut signer, &ca, &[UserID::from(ca_userid)],
|
||||
match certify(config, &mut signer, &ca, &[UserID::from(ca_userid)],
|
||||
Some(config.time), 1, ca_trust_amount)
|
||||
{
|
||||
Err(err) => {
|
||||
@ -308,7 +324,7 @@ fn certify_downloads(config: &mut Config,
|
||||
};
|
||||
|
||||
match certify(
|
||||
&mut ca_signer, &cert, &userids[..],
|
||||
config, &mut ca_signer, &cert, &userids[..],
|
||||
Some(config.time), 0, sequoia_wot::FULLY_TRUSTED)
|
||||
{
|
||||
Ok(cert) => cert,
|
||||
|
Loading…
x
Reference in New Issue
Block a user