From 52fdea48e2b22bff23c656e3c4147e4f4567fd78 Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Thu, 12 Dec 2024 09:59:07 +0100 Subject: [PATCH] Add tests for sq key userid revoke. - Test that the user ID designators behave correctly. --- tests/integration/sq_key_userid_revoke.rs | 147 ++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/tests/integration/sq_key_userid_revoke.rs b/tests/integration/sq_key_userid_revoke.rs index cdf3822e..9b716660 100644 --- a/tests/integration/sq_key_userid_revoke.rs +++ b/tests/integration/sq_key_userid_revoke.rs @@ -2,6 +2,8 @@ use std::collections::BTreeSet; use sequoia_openpgp as openpgp; use openpgp::Cert; +use openpgp::KeyHandle; +use openpgp::Result; use openpgp::cert::amalgamation::ValidAmalgamation; use openpgp::parse::Parse; use openpgp::types::RevocationStatus; @@ -195,3 +197,148 @@ fn allow_non_canonical_userid() { "bye, bye", updated_path.as_path()); } + +#[test] +fn userid_designators() { + let self_signed_email = "alice@example.org"; + let self_signed_userid + = &format!("Alice <{}>", self_signed_email); + + let other_email = "alice@other.org"; + let other_userid = &format!("Alice <{}>", other_email); + + let setup = || { + let mut sq = Sq::new(); + + let (cert, cert_path, _rev_path) + = sq.key_generate(&[], &[ self_signed_userid ]); + sq.key_import(cert_path); + + // Link the self-signed user ID. + sq.pki_link_add(&[], cert.key_handle(), + &[ self_signed_userid ]); + + // Link a non-self-signed user ID. + sq.pki_link_add(&[], cert.key_handle(), + &[ UserIDArg::AddUserID(other_userid) ]); + + sq.tick(1); + + let fpr = cert.fingerprint().to_string(); + + (cert, fpr, sq) + }; + + let revoke = |sq: &Sq, kh: KeyHandle, userid: UserIDArg| + -> Result<()> + { + let rev_path = sq.scratch_file("revocation"); + sq.key_userid_revoke_maybe( + &[], kh, userid, + "retired", "xxx", rev_path.as_path())?; + sq.cert_import(rev_path); + Ok(()) + }; + + // Currently, sq doesn't support first-party revocations on user + // ID that are not self signed. See: + // + // https://gitlab.com/sequoia-pgp/sequoia-sq/-/issues/499 + // + // As such, we check by hand if there is a first-party revocation + // for the specified user ID. + let revocations = |sq: &Sq, kh: KeyHandle, userid: &str, count: usize| + { + let cert = sq.cert_export(&kh); + for ua in cert.userids() { + if &String::from_utf8_lossy(ua.userid().value()) == userid { + assert_eq!(ua.self_revocations().count(), count); + return; + } + } + + if count > 0 { + panic!("{} does not contain {:?}", kh, userid); + } + }; + + // 1. --user: use the specified self-signed user ID. + let (cert, fpr, sq) = setup(); + + // Self-signed and authenticated. + assert!(sq.pki_authenticate( + &[], &fpr, UserIDArg::UserID(self_signed_userid)).is_ok()); + assert!(revoke(&sq, cert.key_handle(), + UserIDArg::UserID(self_signed_userid)).is_ok()); + revocations(&sq, cert.key_handle(), self_signed_userid, 1); + assert!(sq.pki_authenticate( + &[], &fpr, UserIDArg::UserID(self_signed_userid)).is_err()); + + // Authenticated, but not self-signed. + assert!(revoke(&sq, cert.key_handle(), + UserIDArg::UserID(other_userid)).is_err()); + revocations(&sq, cert.key_handle(), other_userid, 0); + assert!(sq.pki_authenticate( + &[], &fpr, UserIDArg::UserID(other_userid)).is_ok()); + + // 2. --userid-or-add: use the specified user ID. + let (cert, fpr, sq) = setup(); + + // Self-signed and authenticated. + assert!(sq.pki_authenticate( + &[], &fpr, UserIDArg::UserID(self_signed_userid)).is_ok()); + assert!(revoke(&sq, cert.key_handle(), + UserIDArg::AddUserID(self_signed_userid)).is_ok()); + revocations(&sq, cert.key_handle(), self_signed_userid, 1); + assert!(sq.pki_authenticate( + &[], &fpr, UserIDArg::UserID(self_signed_userid)).is_err()); + + // Authenticated, but not self-signed. + assert!(sq.pki_authenticate( + &[], &fpr, UserIDArg::UserID(other_userid)).is_ok()); + assert!(revoke(&sq, cert.key_handle(), + UserIDArg::AddUserID(other_userid)).is_ok()); + revocations(&sq, cert.key_handle(), other_userid, 1); + + // 3. --email: use the self-signed user ID with the specified + // email address. + let (cert, fpr, sq) = setup(); + + // Self-signed and authenticated. + assert!(sq.pki_authenticate( + &[], &fpr, UserIDArg::UserID(self_signed_userid)).is_ok()); + assert!(revoke(&sq, cert.key_handle(), + UserIDArg::Email(self_signed_email)).is_ok()); + revocations(&sq, cert.key_handle(), self_signed_userid, 1); + assert!(sq.pki_authenticate( + &[], &fpr, UserIDArg::UserID(self_signed_userid)).is_err()); + + // Authenticated, but not self-signed. + assert!(sq.pki_authenticate( + &[], &fpr, UserIDArg::UserID(other_userid)).is_ok()); + assert!(revoke(&sq, cert.key_handle(), + UserIDArg::Email(other_email)).is_err()); + revocations(&sq, cert.key_handle(), other_userid, 0); + + // 4. --email-or-add: use the self-signed user ID with the + // specified email address, or use a user ID with the email + // address. + let (cert, fpr, sq) = setup(); + + // Self-signed and authenticated. + assert!(sq.pki_authenticate( + &[], &fpr, UserIDArg::UserID(self_signed_userid)).is_ok()); + assert!(revoke(&sq, cert.key_handle(), + UserIDArg::AddEmail(self_signed_email)).is_ok()); + revocations(&sq, cert.key_handle(), self_signed_userid, 1); + assert!(sq.pki_authenticate( + &[], &fpr, UserIDArg::UserID(self_signed_userid)).is_err()); + + // Authenticated, but not self-signed. + assert!(sq.pki_authenticate( + &[], &fpr, UserIDArg::UserID(other_userid)).is_ok()); + assert!(revoke(&sq, cert.key_handle(), + UserIDArg::AddEmail(other_email)).is_ok()); + revocations(&sq, cert.key_handle(), other_userid, 0); + revocations(&sq, cert.key_handle(), &format!("<{}>", other_email), 1); +}