summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2021-01-21 12:39:02 +0100
committerJustus Winter <justus@sequoia-pgp.org>2021-01-21 12:39:02 +0100
commit6e555106da58e943a7f2a3091c89c282232fc968 (patch)
treee5720d4505c8f20c1966d5ea7511f8a5dc28d005
parentdee5ed06846b7eb9167a19128da100532330271f (diff)
sq: Make it build with sequoia-openpgp 1.0.0.
- This backports a few functions that are not yet available in sequoia-openpgp 1.0.0, and disables a test covering an odd corner case. - Once sq depends on sequoia-openpgp 1.1.0, this commit can be reverted.
-rw-r--r--sq/src/commands/key.rs92
-rw-r--r--sq/src/sq.rs5
-rw-r--r--sq/tests/sq-certify.rs6
-rw-r--r--sq/tests/sq-key-adopt.rs5
4 files changed, 100 insertions, 8 deletions
diff --git a/sq/src/commands/key.rs b/sq/src/commands/key.rs
index b2d7ed3f..69904ebc 100644
--- a/sq/src/commands/key.rs
+++ b/sq/src/commands/key.rs
@@ -201,8 +201,8 @@ pub fn adopt(m: &ArgMatches, p: &dyn Policy) -> Result<()> {
// Gather the Key IDs / Fingerprints and make sure they are valid.
for id in m.values_of("key").unwrap_or_default() {
- let h = id.parse::<KeyHandle>()?;
- if h.is_invalid() {
+ let h = keyhandle_from_str(&id)?;
+ if keyhandle_is_invalid(&h) {
return Err(anyhow::anyhow!(
"Invalid Fingerprint or KeyID ('{:?}')", id));
}
@@ -289,7 +289,7 @@ pub fn adopt(m: &ArgMatches, p: &dyn Policy) -> Result<()> {
if missing.len() > 0 {
return Err(anyhow::anyhow!(
"Keys not found: {}",
- missing.iter().map(|&h| h.to_hex()).join(", ")));
+ missing.iter().map(|&h| format!("{:X}", h)).join(", ")));
}
@@ -356,7 +356,10 @@ pub fn adopt(m: &ArgMatches, p: &dyn Policy) -> Result<()> {
let cert = cert.clone().insert_packets(packets.clone())?;
- cert.as_tsk().armored().serialize(&mut std::io::stdout())?;
+ let mut message = crate::create_or_stdout_pgp(
+ None, false, false, sequoia_openpgp::armor::Kind::SecretKey)?;
+ cert.as_tsk().serialize(&mut message)?;
+ message.finalize()?;
let vc = cert.with_policy(p, None).expect("still valid");
for pair in packets[..].chunks(2) {
@@ -441,7 +444,7 @@ pub fn attest_certifications(m: &ArgMatches, _p: &dyn Policy) -> Result<()> {
if m.is_present("all") {
for certification in uid.certifications() {
let mut h = hash_algo.context()?;
- certification.hash_for_confirmation(&mut h);
+ hash_for_confirmation(certification, &mut h);
attestations.push(h.into_digest()?);
}
}
@@ -483,6 +486,83 @@ pub fn attest_certifications(m: &ArgMatches, _p: &dyn Policy) -> Result<()> {
// Finally, add the new signatures.
let key = key.insert_packets(attestation_signatures)?;
- key.as_tsk().armored().serialize(&mut std::io::stdout())?;
+ let mut message = crate::create_or_stdout_pgp(
+ None, false, false, sequoia_openpgp::armor::Kind::SecretKey)?;
+ key.as_tsk().serialize(&mut message)?;
+ message.finalize()?;
Ok(())
}
+
+// XXX: The following functions are backports from sequoia-openpgp
+// 1.1. Remove them by reverting the commit that introduced them once
+// sequoia-sq depends on a newer version of sequoia-openpgp.
+
+fn keyhandle_from_str(s: &str) -> Result<KeyHandle> {
+ use sequoia_openpgp::{Fingerprint, KeyID};
+ let bytes = &sequoia_openpgp::fmt::hex::decode_pretty(s)?[..];
+ match Fingerprint::from_bytes(bytes) {
+ fpr @ Fingerprint::Invalid(_) => {
+ match KeyID::from_bytes(bytes) {
+ // If it can't be parsed as either a Fingerprint or a
+ // KeyID, return Fingerprint::Invalid.
+ KeyID::Invalid(_) => Ok(fpr.into()),
+ kid => Ok(kid.into()),
+ }
+ }
+ fpr => Ok(fpr.into()),
+ }
+}
+
+fn keyhandle_is_invalid(h: &KeyHandle) -> bool {
+ use sequoia_openpgp::{Fingerprint, KeyID};
+ match h {
+ KeyHandle::Fingerprint(Fingerprint::Invalid(_)) => true,
+ KeyHandle::KeyID(KeyID::Invalid(_)) => true,
+ _ => false,
+ }
+}
+
+/// Hashes this signature for use in a Third-Party Confirmation
+/// signature.
+use sequoia_openpgp::{crypto::hash::Digest, packet::Signature};
+pub fn hash_for_confirmation(sig: &Signature, hash: &mut dyn Digest) {
+ use sequoia_openpgp::serialize::{Marshal, MarshalInto};
+ // Section 5.2.4 of RFC4880:
+ //
+ // > When a signature is made over a Signature packet (type
+ // > 0x50), the hash data starts with the octet 0x88, followed
+ // > by the four-octet length of the signature, and then the
+ // > body of the Signature packet. (Note that this is an
+ // > old-style packet header for a Signature packet with the
+ // > length-of-length set to zero.) The unhashed subpacket
+ // > data of the Signature packet being hashed is not included
+ // > in the hash, and the unhashed subpacket data length value
+ // > is set to zero.
+
+ // This code assumes that the signature has been verified
+ // prior to being confirmed, so it is well-formed.
+ let mut body = Vec::new();
+ body.push(sig.version());
+ body.push(sig.typ().into());
+ body.push(sig.pk_algo().into());
+ body.push(sig.hash_algo().into());
+
+ // The hashed area.
+ let l = sig.hashed_area().serialized_len()
+ // Assumes well-formedness.
+ .min(std::u16::MAX as usize);
+ body.extend(&(l as u16).to_be_bytes());
+ // Assumes well-formedness.
+ let _ = sig.hashed_area().serialize(&mut body);
+
+ // The unhashed area.
+ body.extend(&[0, 0]); // Size replaced by zero.
+ // Unhashed packets omitted.
+
+ body.extend(sig.digest_prefix());
+ let _ = sig.mpis().serialize(&mut body);
+
+ hash.update(&[0x88]);
+ hash.update(&(body.len() as u32).to_be_bytes());
+ hash.update(&body);
+}
diff --git a/sq/src/sq.rs b/sq/src/sq.rs
index 1373bf41..8f4707af 100644
--- a/sq/src/sq.rs
+++ b/sq/src/sq.rs
@@ -304,6 +304,11 @@ fn main() -> Result<()> {
let policy = &mut P::new();
+ // XXX: Compat with sequoia-openpgp 1.0.0:
+ use openpgp::packet::signature::subpacket::SubpacketTag;
+ policy.accept_critical_subpacket(SubpacketTag::TrustSignature);
+ policy.accept_critical_subpacket(SubpacketTag::RegularExpression);
+
let matches = sq_cli::build().get_matches();
let known_notations: Vec<&str> = matches.values_of("known-notation")
diff --git a/sq/tests/sq-certify.rs b/sq/tests/sq-certify.rs
index 7dbc8d99..81a2fdfe 100644
--- a/sq/tests/sq-certify.rs
+++ b/sq/tests/sq-certify.rs
@@ -122,7 +122,11 @@ fn sq_certify() -> Result<()> {
"--expires-in", "1d",
])
.stdout().satisfies(|output| {
- let p = &StandardPolicy::new();
+ let p = &mut StandardPolicy::new();
+ // XXX: Compat with sequoia-openpgp 1.0.0:
+ use openpgp::packet::signature::subpacket::SubpacketTag;
+ p.accept_critical_subpacket(SubpacketTag::TrustSignature);
+ p.accept_critical_subpacket(SubpacketTag::RegularExpression);
let cert = Cert::from_bytes(output).unwrap();
let vc = cert.with_policy(p, None).unwrap();
diff --git a/sq/tests/sq-key-adopt.rs b/sq/tests/sq-key-adopt.rs
index 5bb40f32..0bebe2a4 100644
--- a/sq/tests/sq-key-adopt.rs
+++ b/sq/tests/sq-key-adopt.rs
@@ -255,7 +255,10 @@ mod integration {
Ok(())
}
- #[test]
+ // XXX: Compat with sequoia-openpgp 1.0.0, which just doesn't
+ // handle this correctly. However, this case is a bit bonkers, so
+ // we'll just ignore it for now.
+ #[allow(dead_code)]
fn adopt_own_primary() -> Result<()> {
// Adopt own primary key.
Assert::cargo_binary("sq").with_args(&[