don't allow fetch by revoked UIDs

closes #15
This commit is contained in:
Kai Michaelis 2019-01-15 16:59:35 +01:00
parent 8f2f1b36ff
commit c503e52204
4 changed files with 93 additions and 17 deletions

View File

@ -366,4 +366,12 @@ mod tests {
test::test_kid_lookup(&mut db);
}
#[test]
fn uid_revocation() {
let tmpdir = TempDir::new().unwrap();
let mut db = Filesystem::new(tmpdir.path()).unwrap();
test::test_uid_revocation(&mut db);
}
}

View File

@ -170,4 +170,11 @@ mod tests {
test::test_kid_lookup(&mut db);
}
#[test]
fn uid_revocation() {
let mut db = Memory::default();
test::test_uid_revocation(&mut db);
}
}

View File

@ -143,29 +143,35 @@ pub trait Database: Sync + Send {
Ok(())
}
fn unlink_userids(&self, fpr: &Fingerprint, userids: Vec<Email>) {
for uid in userids {
self.unlink_email(&uid, fpr);
}
}
fn merge_or_publish(&self, mut tpk: TPK) -> Result<Vec<(Email, String)>> {
use sequoia_openpgp::RevocationStatus;
let fpr = Fingerprint::try_from(tpk.primary().fingerprint())?;
let mut ret = Vec::default();
let mut active_uids = Vec::default();
let mut revoked_uids = Vec::default();
// update verify tokens
for uid in tpk.userids() {
let email = Email::try_from(uid.userid().clone())?;
match uid.revoked() {
RevocationStatus::Revoked(_) => { /* skip */ }
RevocationStatus::CouldBe(_) |
RevocationStatus::NotAsFarAsWeKnow => {
let email = Email::try_from(uid.userid().clone())?;
if self.by_email(&email).is_none() {
let payload = Verify::new(
uid.userid(),
&uid.selfsigs().collect::<Vec<_>>(),
fpr.clone())?;
ret.push((email, self.new_verify_token(payload)?));
}
RevocationStatus::CouldBe(_) | RevocationStatus::Revoked(_) => {
revoked_uids.push(email);
}
RevocationStatus::NotAsFarAsWeKnow if self.by_email(&email).is_none() => {
let payload = Verify::new(
uid.userid(),
&uid.selfsigs().collect::<Vec<_>>(),
fpr.clone())?;
active_uids.push((email, self.new_verify_token(payload)?));
}
_ => {}
}
}
@ -183,7 +189,8 @@ pub trait Database: Sync + Send {
if self.compare_and_swap(&fpr, Some(&old), Some(&new))? {
self.link_subkeys(&fpr, subkeys)?;
return Ok(ret);
self.unlink_userids(&fpr, revoked_uids);
return Ok(active_uids);
}
}
@ -192,7 +199,8 @@ pub trait Database: Sync + Send {
if self.compare_and_swap(&fpr, None, Some(&fresh))? {
self.link_subkeys(&fpr, subkeys)?;
return Ok(ret);
self.unlink_userids(&fpr, revoked_uids);
return Ok(active_uids);
}
}
}

View File

@ -19,7 +19,7 @@ use std::str::FromStr;
use database::Database;
use sequoia_openpgp::tpk::{TPKBuilder, UserIDBinding};
use sequoia_openpgp::{Packet, packet::UserID, TPK, PacketPile, parse::Parse};
use sequoia_openpgp::{Packet, packet::UserID, TPK, PacketPile, parse::Parse, RevocationStatus, constants::ReasonForRevocation, constants::SignatureType};
use types::{KeyID, Email, Fingerprint};
pub fn test_uid_verification<D: Database>(db: &mut D) {
@ -317,3 +317,56 @@ pub fn test_kid_lookup<D: Database>(db: &mut D) {
assert_eq!(raw1, raw2);
assert_eq!(raw1, raw3);
}
pub fn test_uid_revocation<D: Database>(db: &mut D) {
use std::{thread, time};
let str_uid1 = "Test A <test_a@example.com>";
let str_uid2 = "Test B <test_b@example.com>";
let tpk = TPKBuilder::default()
.add_userid(str_uid1)
.add_userid(str_uid2)
.generate().unwrap().0;
let mut uid1 = UserID::new();
let mut uid2 = UserID::new();
uid1.set_userid_from_bytes(str_uid1.as_bytes());
uid2.set_userid_from_bytes(str_uid2.as_bytes());
let email1 = Email::from_str(str_uid1).unwrap();
let email2 = Email::from_str(str_uid2).unwrap();
// upload key
let tokens = db.merge_or_publish(tpk.clone()).unwrap();
let fpr = Fingerprint::try_from(tpk.fingerprint()).unwrap();
// verify uid
assert_eq!(tokens.len(), 2);
assert!(db.verify_token(&tokens[0].1).unwrap().is_some());
assert!(db.verify_token(&tokens[1].1).unwrap().is_some());
// fetch both uids
assert!(db.by_email(&email1).is_some());
assert!(db.by_email(&email2).is_some());
thread::sleep(time::Duration::from_secs(2));
// revoke one uid
let sig = {
let uid = tpk.userids().find(|b| *b.userid() == uid2).unwrap();
assert_eq!(RevocationStatus::NotAsFarAsWeKnow, uid.revoked());
let mut keypair = tpk.primary().clone().into_keypair().unwrap();
uid.revoke(&mut keypair,
ReasonForRevocation::UIDRetired,
b"It was the maid :/").unwrap()
};
assert_eq!(sig.sigtype(), SignatureType::CertificateRevocation);
let tpk = tpk.merge_packets(vec![sig.to_packet()]).unwrap();
let tokens = db.merge_or_publish(tpk.clone()).unwrap();
assert_eq!(tokens.len(), 0);
// fail to fetch by one uid, fail by another
assert!(db.by_email(&email1).is_some());
assert!(db.by_email(&email2).is_none());
}