diff options
-rw-r--r-- | ffi/src/error.rs | 2 | ||||
-rw-r--r-- | openpgp-ffi/src/cert.rs | 5 | ||||
-rw-r--r-- | openpgp-ffi/src/error.rs | 6 | ||||
-rw-r--r-- | openpgp-ffi/src/parse/stream.rs | 6 | ||||
-rw-r--r-- | openpgp/src/cert/builder.rs | 24 | ||||
-rw-r--r-- | openpgp/src/cert/key_amalgamation.rs | 154 | ||||
-rw-r--r-- | openpgp/src/cert/keyiter.rs | 14 | ||||
-rw-r--r-- | openpgp/src/lib.rs | 4 | ||||
-rw-r--r-- | openpgp/src/parse/stream.rs | 16 | ||||
-rw-r--r-- | sqv/src/sqv.rs | 2 |
10 files changed, 132 insertions, 101 deletions
diff --git a/ffi/src/error.rs b/ffi/src/error.rs index 1bcf051c..5b1c6ea0 100644 --- a/ffi/src/error.rs +++ b/ffi/src/error.rs @@ -74,6 +74,8 @@ impl<'a> FromSequoiaError<'a> for Status { Status::Expired, &openpgp::Error::NotYetLive(_) => Status::NotYetLive, + &openpgp::Error::NoBindingSignature(_) => + Status::NoBindingSignature, openpgp::Error::__Nonexhaustive => unreachable!(), } } diff --git a/openpgp-ffi/src/cert.rs b/openpgp-ffi/src/cert.rs index 2d18ff18..cfa490ac 100644 --- a/openpgp-ffi/src/cert.rs +++ b/openpgp-ffi/src/cert.rs @@ -767,9 +767,8 @@ pub extern "C" fn pgp_cert_valid_key_iter_next<'a>( iter_wrapper.next_called = true; if let Some(ka) = iter_wrapper.iter.next() { - // XXX: Shouldn't assume the current time. - let sig = ka.binding_signature(None); - let rs = ka.revoked(None); + let sig = ka.binding_signature(); + let rs = ka.revoked(); let key = ka.key(); if let Some(ptr) = sigo { diff --git a/openpgp-ffi/src/error.rs b/openpgp-ffi/src/error.rs index 2277d9a2..43b2b63d 100644 --- a/openpgp-ffi/src/error.rs +++ b/openpgp-ffi/src/error.rs @@ -153,6 +153,9 @@ pub enum Status { /// Not yet live. NotYetLive = -31, + + /// No binding signature. + NoBindingSignature = -32, } /// Returns the error message. @@ -195,6 +198,7 @@ pub extern "C" fn pgp_status_to_string(status: Status) -> *const c_char { UnsupportedCert => "Cert not supported\x00", Expired => "Expired\x00", NotYetLive => "Not yet live\x00", + NoBindingSignature => "No binding signature\x00", }.as_bytes().as_ptr() as *const c_char } @@ -250,6 +254,8 @@ impl<'a> From<&'a failure::Error> for Status { Status::Expired, &openpgp::Error::NotYetLive(_) => Status::NotYetLive, + &openpgp::Error::NoBindingSignature(_) => + Status::NoBindingSignature, openpgp::Error::__Nonexhaustive => unreachable!(), } } diff --git a/openpgp-ffi/src/parse/stream.rs b/openpgp-ffi/src/parse/stream.rs index ae3fde7a..49778ad1 100644 --- a/openpgp-ffi/src/parse/stream.rs +++ b/openpgp-ffi/src/parse/stream.rs @@ -190,7 +190,7 @@ fn $fn_name<'a>( -> bool { use self::stream::VerificationResult::*; - if let $variant { sig, cert, ka, time } = result.ref_raw() { + if let $variant { sig, cert, ka } = result.ref_raw() { if let Some(mut p) = sig_r { *unsafe { p.as_mut() } = sig.move_into_raw(); } @@ -207,10 +207,10 @@ fn $fn_name<'a>( } if let Some(mut p) = binding_r { *unsafe { p.as_mut() } = - ka.binding_signature(*time).move_into_raw(); + ka.binding_signature().move_into_raw(); } if let Some(mut p) = revocation_status_r { - *unsafe { p.as_mut() } = ka.revoked(*time).move_into_raw(); + *unsafe { p.as_mut() } = ka.revoked().move_into_raw(); } true } else { diff --git a/openpgp/src/cert/builder.rs b/openpgp/src/cert/builder.rs index c33633da..d870be1f 100644 --- a/openpgp/src/cert/builder.rs +++ b/openpgp/src/cert/builder.rs @@ -655,22 +655,18 @@ mod tests { assert!(sig.key_alive(key, now + 590 * s).is_ok()); assert!(! sig.key_alive(key, now + 610 * s).is_ok()); - let (sig, key) = cert.keys().policy(now).alive().revoked(false) + let ka = cert.keys().policy(now).alive().revoked(false) .for_signing() - .nth(0).map(|ka| { - (ka.binding_signature(now).unwrap(), ka.key()) - }).unwrap(); - assert!(sig.key_alive(key, now).is_ok()); - assert!(sig.key_alive(key, now + 290 * s).is_ok()); - assert!(! sig.key_alive(key, now + 310 * s).is_ok()); + .nth(0).unwrap(); + assert!(ka.alive().is_ok()); + assert!(ka.clone().set_time(now + 290 * s).alive().is_ok()); + assert!(! ka.clone().set_time(now + 310 * s).alive().is_ok()); - let (sig, key) = cert.keys().policy(now).alive().revoked(false) + let ka = cert.keys().policy(now).alive().revoked(false) .for_authentication() - .nth(0).map(|ka| { - (ka.binding_signature(now).unwrap(), ka.key()) - }).unwrap(); - assert!(sig.key_alive(key, now).is_ok()); - assert!(sig.key_alive(key, now + 590 * s).is_ok()); - assert!(! sig.key_alive(key, now + 610 * s).is_ok()); + .nth(0).unwrap(); + assert!(ka.alive().is_ok()); + assert!(ka.clone().set_time(now + 590 * s).alive().is_ok()); + assert!(! ka.clone().set_time(now + 610 * s).alive().is_ok()); } } diff --git a/openpgp/src/cert/key_amalgamation.rs b/openpgp/src/cert/key_amalgamation.rs index 9d0f9ba5..62f846ae 100644 --- a/openpgp/src/cert/key_amalgamation.rs +++ b/openpgp/src/cert/key_amalgamation.rs @@ -1,4 +1,5 @@ use std::time; +use std::time::SystemTime; use std::convert::TryInto; use std::convert::TryFrom; use std::borrow::Borrow; @@ -6,6 +7,7 @@ use std::borrow::Borrow; use crate::{ Cert, cert::KeyBinding, + Error, packet::key, packet::key::SecretKeyMaterial, packet::Key, @@ -16,17 +18,19 @@ use crate::{ }; /// A variant of `KeyAmalgamation` for primary keys. -#[derive(Debug)] +#[derive(Debug, Clone)] struct PrimaryKeyAmalgamation<'a, P: key::KeyParts> { cert: &'a Cert, binding: &'a KeyBinding<P, key::PrimaryRole>, + time: SystemTime, } /// A variant of `KeyAmalgamation` for subkeys. -#[derive(Debug)] +#[derive(Debug, Clone)] struct SubordinateKeyAmalgamation<'a, P: key::KeyParts> { cert: &'a Cert, binding: &'a KeyBinding<P, key::SubordinateRole>, + time: SystemTime, } /// The underlying `KeyAmalgamation` type. @@ -34,36 +38,38 @@ struct SubordinateKeyAmalgamation<'a, P: key::KeyParts> { /// We don't make this type public, because an enum's variant types /// must also all be public, and we don't want that here. Wrapping /// this in a struct means that we can hide that. -#[derive(Debug)] +#[derive(Debug, Clone)] enum KeyAmalgamation0<'a, P: key::KeyParts> { Primary(PrimaryKeyAmalgamation<'a, P>), Subordinate(SubordinateKeyAmalgamation<'a, P>), } /// A `Key` and its associated data. -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct KeyAmalgamation<'a, P: key::KeyParts>(KeyAmalgamation0<'a, P>); -impl<'a, P> From<(&'a Cert, &'a KeyBinding<P, key::PrimaryRole>)> +impl<'a, P> From<(&'a Cert, &'a KeyBinding<P, key::PrimaryRole>, SystemTime)> for KeyAmalgamation<'a, P> where P: key::KeyParts { - fn from(x: (&'a Cert, &'a KeyBinding<P, key::PrimaryRole>)) -> Self { + fn from(x: (&'a Cert, &'a KeyBinding<P, key::PrimaryRole>, SystemTime)) -> Self { KeyAmalgamation(KeyAmalgamation0::Primary(PrimaryKeyAmalgamation { cert: x.0, binding: x.1, + time: x.2, })) } } -impl<'a, P> From<(&'a Cert, &'a KeyBinding<P, key::SubordinateRole>)> +impl<'a, P> From<(&'a Cert, &'a KeyBinding<P, key::SubordinateRole>, SystemTime)> for KeyAmalgamation<'a, P> where P: key::KeyParts { - fn from(x: (&'a Cert, &'a KeyBinding<P, key::SubordinateRole>)) -> Self { + fn from(x: (&'a Cert, &'a KeyBinding<P, key::SubordinateRole>, SystemTime)) -> Self { KeyAmalgamation(KeyAmalgamation0::Subordinate(SubordinateKeyAmalgamation { cert: x.0, binding: x.1, + time: x.2, })) } } @@ -80,6 +86,7 @@ impl<'a> From<KeyAmalgamation<'a, key::PublicParts>> PrimaryKeyAmalgamation { cert: ka.cert, binding: ka.binding.into(), + time: ka.time, }) ) } @@ -88,6 +95,7 @@ impl<'a> From<KeyAmalgamation<'a, key::PublicParts>> SubordinateKeyAmalgamation { cert: ka.cert, binding: ka.binding.into(), + time: ka.time, }) ) } @@ -105,6 +113,7 @@ impl<'a> From<KeyAmalgamation<'a, key::SecretParts>> PrimaryKeyAmalgamation { cert: ka.cert, binding: ka.binding.into(), + time: ka.time, }) ) } @@ -113,6 +122,7 @@ impl<'a> From<KeyAmalgamation<'a, key::SecretParts>> SubordinateKeyAmalgamation { cert: ka.cert, binding: ka.binding.into(), + time: ka.time, }) ) } @@ -132,6 +142,7 @@ impl<'a> TryFrom<KeyAmalgamation<'a, key::PublicParts>> PrimaryKeyAmalgamation { cert: ka.cert, binding: ka.binding.try_into()?, + time: ka.time, }) ) } @@ -140,6 +151,7 @@ impl<'a> TryFrom<KeyAmalgamation<'a, key::PublicParts>> SubordinateKeyAmalgamation { cert: ka.cert, binding: ka.binding.try_into()?, + time: ka.time, }) ) } @@ -160,44 +172,76 @@ impl<'a, P: 'a + key::KeyParts> KeyAmalgamation<'a, P> { } } - /// Returns the key's binding signature at time `t`, if any. - pub fn binding_signature<T>(&self, t: T) -> Option<&'a Signature> + /// Returns the amalgamation's reference time. + /// + /// For queries that are with respect to a point in time, this + /// determines that point in time. For instance, if a key is + /// created at `t_c` and expires at `t_e`, then + /// `KeyAmalgamation::alive` will return true if the reference + /// time is greater than or equal to `t_c` and less than `t_e`. + pub fn time(&self) -> SystemTime { + match self { + KeyAmalgamation(KeyAmalgamation0::Primary(ref h)) => + h.time, + KeyAmalgamation(KeyAmalgamation0::Subordinate(ref h)) => + h.time, + } + } + + /// Changes the amalgamation's reference time. + /// + /// If `time` is `None`, the current time is used. + pub fn set_time<T>(mut self, time: T) -> Self where T: Into<Option<time::SystemTime>> { + let time = time.into().unwrap_or_else(SystemTime::now); + match self { + KeyAmalgamation(KeyAmalgamation0::Primary(ref mut h)) => + h.time = time, + KeyAmalgamation(KeyAmalgamation0::Subordinate(ref mut h)) => + h.time = time, + } + + self + } + + /// Returns the key's binding signature as of the reference time, + /// if any. + pub fn binding_signature(&self) -> Option<&'a Signature> + { match self { KeyAmalgamation(KeyAmalgamation0::Primary(ref h)) => - h.cert.primary_key_signature(t), + h.cert.primary_key_signature(self.time()), KeyAmalgamation(KeyAmalgamation0::Subordinate(ref h)) => - h.binding.binding_signature(t), + h.binding.binding_signature(self.time()), } } - /// Returns the key's revocation status at time `t`. - pub fn revoked<T>(&self, t: T) -> RevocationStatus<'a> - where T: Into<Option<time::SystemTime>> + /// Returns the key's revocation status as of the amalgamtion's + /// reference time. + pub fn revoked(&self) -> RevocationStatus<'a> { match self { KeyAmalgamation(KeyAmalgamation0::Primary(ref h)) => - h.cert.revoked(t), + h.cert.revoked(self.time()), KeyAmalgamation(KeyAmalgamation0::Subordinate(ref h)) => - h.binding.revoked(t), + h.binding.revoked(self.time()), } } - /// Returns the key's key flags at time `time`. - pub fn key_flags<T>(&self, time: T) -> Option<KeyFlags> - where T: Into<Option<time::SystemTime>> + /// Returns the key's key flags as of the amalgamtion's + /// reference time. + pub fn key_flags(&self) -> Option<KeyFlags> { - self.binding_signature(time).map(|sig| sig.key_flags()) + self.binding_signature().map(|sig| sig.key_flags()) } /// Returns whether the key has at least one of the specified key - /// flags at time `time`. - pub fn has_any_key_flag<T, F>(&self, time: T, flags: F) -> bool - where T: Into<Option<time::SystemTime>>, - F: Borrow<KeyFlags> + /// flags as of the amalgamtion's reference time. + pub fn has_any_key_flag<F>(&self, flags: F) -> bool + where F: Borrow<KeyFlags> { - if let Some(our_flags) = self.key_flags(time) { + if let Some(our_flags) = self.key_flags() { !(&our_flags & flags.borrow()).is_empty() } else { // We have no key flags. @@ -205,52 +249,48 @@ impl<'a, P: 'a + key::KeyParts> KeyAmalgamation<'a, P> { } } - /// Returns whether key is certification capable at time `time`. - pub fn for_certification<T>(&self, time: T) -> bool - where T: Into<Option<time::SystemTime>> - { - self.has_any_key_flag(time, KeyFlags::empty().set_certification(true)) + /// Returns whether key is certification capable as of the + /// amalgamtion's reference time. + pub fn for_certification(&self) -> bool { + self.has_any_key_flag(KeyFlags::empty().set_certification(true)) } - /// Returns whether key is signing capable at time `time`. - pub fn for_signing<T>(&self, time: T) -> bool - where T: Into<Option<time::SystemTime>> - { - self.has_any_key_flag(time, KeyFlags::empty().set_signing(true)) + /// Returns whether key is signing capable as of the amalgamtion's + /// reference time. + pub fn for_signing(&self) -> bool { + self.has_any_key_flag(KeyFlags::empty().set_signing(true)) } - /// Returns whether key is authentication capable at time `time`. - pub fn for_authentication<T>(&self, time: T) -> bool - where T: Into<Option<time::SystemTime>> + /// Returns whether key is authentication capable as of the + /// amalgamtion's reference time. + pub fn for_authentication(&self) -> bool { - self.has_any_key_flag(time, KeyFlags::empty().set_authentication(true)) + self.has_any_key_flag(KeyFlags::empty().set_authentication(true)) } - /// Returns whether key is intended for storage encryption at time - /// `time`. - pub fn for_storage_encryption<T>(&self, time: T) -> bool - where T: Into<Option<std::time::SystemTime>> + /// Returns whether key is intended for storage encryption as of + /// the amalgamtion's reference time. + pub fn for_storage_encryption(&self) -> bool { - self.has_any_key_flag(time, KeyFlags::empty().set_storage_encryption(true)) + self.has_any_key_flag(KeyFlags::empty().set_storage_encryption(true)) } - /// Returns whether key is intended for transport encryption at - /// time `time`. - pub fn for_transport_encryption<T>(&self, time: T) -> bool - where T: Into<Option<std::time::SystemTime>> + /// Returns whether key is intended for transport encryption as of the + /// amalgamtion's reference time. + pub fn for_transport_encryption(&self) -> bool { - self.has_any_key_flag(time, KeyFlags::empty().set_transport_encryption(true)) + self.has_any_key_flag(KeyFlags::empty().set_transport_encryption(true)) } - /// Returns whether the key is alive at time `time`. - pub fn alive<T>(&self, time: T) -> bool - where T: Into<Option<std::time::SystemTime>>, - &'a Key<P, key::UnspecifiedRole>: From<&'a key::PublicKey> + /// Returns whether the key is alive as of the amalgamtion's + /// reference time. + pub fn alive(&self) -> Result<()> + where &'a Key<P, key::UnspecifiedRole>: From<&'a key::PublicKey> { - if let Some(sig) = self.binding_signature(None) { - sig.key_alive(self.key(), time).is_ok() + if let Some(sig) = self.binding_signature() { + sig.key_alive(self.key(), self.time()) } else { - false + Err(Error::NoBindingSignature(self.time()).into()) } } diff --git a/openpgp/src/cert/keyiter.rs b/openpgp/src/cert/keyiter.rs index f235ec89..752c457f 100644 --- a/openpgp/src/cert/keyiter.rs +++ b/openpgp/src/cert/keyiter.rs @@ -351,16 +351,16 @@ impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> ValidKeyIter<'a, P, R> { loop { let ka : KeyAmalgamation<'a, key::PublicParts> = if ! self.primary { self.primary = true; - (cert, &cert.primary).into() + (cert, &cert.primary, self.time).into() } else { - (cert, self.subkey_iter.next()?).into() + (cert, self.subkey_iter.next()?, self.time).into() }; let key = ka.key(); t!("Considering key: {:?}", key); let binding_signature - = if let Some(binding_signature) = ka.binding_signature(self.time) { + = if let Some(binding_signature) = ka.binding_signature() { binding_signature } else { t!("No self-signature at time {:?}", self.time); @@ -368,7 +368,7 @@ impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> ValidKeyIter<'a, P, R> { }; if let Some(flags) = self.flags.as_ref() { - if (&binding_signature.key_flags() & &flags).is_empty() { + if !ka.has_any_key_flag(flags) { t!("Have flags: {:?}, want flags: {:?}... skipping.", binding_signature.key_flags(), flags); continue; @@ -376,14 +376,14 @@ impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> ValidKeyIter<'a, P, R> { } if let Some(()) = self.alive { - if let Err(err) = binding_signature.key_alive(key, self.time) { + if let Err(err) = ka.alive() { t!("Key not alive: {:?}", err); continue; } } if let Some(want_revoked) = self.revoked { - if let RevocationStatus::Revoked(_) = ka.revoked(self.time) { + if let RevocationStatus::Revoked(_) = ka.revoked() { // The key is definitely revoked. if ! want_revoked { t!("Key revoked... skipping."); @@ -534,7 +534,7 @@ impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> ValidKeyIter<'a, P, R> /// .keys() /// .policy(None) /// .filter(|ka| { - /// match ka.revoked(None) { + /// match ka.revoked() { /// RevocationStatus::Revoked(_) => /// // It's definitely revoked, skip it. /// false, diff --git a/openpgp/src/lib.rs b/openpgp/src/lib.rs index 56d88528..c436d3b5 100644 --- a/openpgp/src/lib.rs +++ b/openpgp/src/lib.rs @@ -272,6 +272,10 @@ pub enum Error { #[fail(display = "Not live until {:?}", _0)] NotYetLive(std::time::SystemTime), + /// No binding signature. + #[fail(display = "No binding signature at time {:?}", _0)] + NoBindingSignature(std::time::SystemTime), + /// This marks this enum as non-exhaustive. Do not use this /// variant. #[doc(hidden)] #[fail(display = "__Nonexhaustive")] __Nonexhaustive, diff --git a/openpgp/src/parse/stream.rs b/openpgp/src/parse/stream.rs index fda80f62..3926299f 100644 --- a/openpgp/src/parse/stream.rs +++ b/openpgp/src/parse/stream.rs @@ -178,9 +178,6 @@ pub enum VerificationResult<'a> { /// The signing key that made the signature. ka: KeyAmalgamation<'a, key::PublicParts>, - - /// The time at which the signature is evaluated. - time: time::SystemTime, }, /// The signature is good, but it is not alive at the specified @@ -197,9 +194,6 @@ pub enum VerificationResult<'a> { /// The signing key that made the signature. ka: KeyAmalgamation<'a, key::PublicParts>, - - /// The time at which the signature is evaluated. - time: time::SystemTime, }, /// Unable to verify the signature because the key is missing. @@ -218,9 +212,6 @@ pub enum VerificationResult<'a> { /// The signing key that made the signature. ka: KeyAmalgamation<'a, key::PublicParts>, - - /// The time at which the signature is evaluated. - time: time::SystemTime, }, } @@ -699,20 +690,17 @@ impl<'a, H: VerificationHelper> Verifier<'a, H> { VerificationResult::GoodChecksum { sig: sig.clone(), cert, ka, - time: self.time, } } else { VerificationResult::NotAlive { sig: sig.clone(), cert, ka, - time: self.time, } } } else { VerificationResult::BadChecksum { sig: sig.clone(), cert, ka, - time: self.time, } } ); @@ -1609,14 +1597,12 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> { { sig: sig.clone(), cert, ka, - time: self.time, } } else { VerificationResult::GoodChecksum { sig: sig.clone(), cert, ka, - time: self.time, } } } else { @@ -1624,14 +1610,12 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> { VerificationResult::GoodChecksum { sig: sig.clone(), cert, ka, - time: self.time, } } } else { VerificationResult::BadChecksum { sig: sig.clone(), cert, ka, - time: self.time, } } ); diff --git a/sqv/src/sqv.rs b/sqv/src/sqv.rs index e1859132..fec3e1ff 100644 --- a/sqv/src/sqv.rs +++ b/sqv/src/sqv.rs @@ -235,7 +235,7 @@ fn real_main() -> Result<(), failure::Error> { // Find the right key. for ka in cert.keys().policy(None) { // Use the current binding signature. - let binding = match ka.binding_signature(None) { + let binding = match ka.binding_signature() { Some(b) => b, None => continue, }; |