diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2018-06-01 12:17:43 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2018-06-01 12:23:02 +0200 |
commit | 301cd06e41aab0bd646f4664b0b182c97cd8a1dd (patch) | |
tree | 416b8c3be7f8ee8369f5cc09d943c394f25a8fab | |
parent | 4cae004d69eaf56d29537bc626c5b26237c78a64 (diff) |
openpgp: Add convenience functions to check for sig and key expiry.
-rw-r--r-- | openpgp/Cargo.toml | 1 | ||||
-rw-r--r-- | openpgp/src/lib.rs | 2 | ||||
-rw-r--r-- | openpgp/src/parse/subpacket.rs | 75 |
3 files changed, 77 insertions, 1 deletions
diff --git a/openpgp/Cargo.toml b/openpgp/Cargo.toml index 440db815..3d2d4c31 100644 --- a/openpgp/Cargo.toml +++ b/openpgp/Cargo.toml @@ -11,3 +11,4 @@ failure = "0.1.1" flate2 = "1.0.1" nettle = { git = "https://gitlab.com/sequoia-pgp/nettle-rs.git" } quickcheck = "0.6" +time = "0.1.38" diff --git a/openpgp/src/lib.rs b/openpgp/src/lib.rs index 1b090778..4e59946b 100644 --- a/openpgp/src/lib.rs +++ b/openpgp/src/lib.rs @@ -53,6 +53,8 @@ extern crate quickcheck; #[cfg(not(test))] extern crate quickcheck; +extern crate time; + pub mod armor; pub mod ctb; diff --git a/openpgp/src/parse/subpacket.rs b/openpgp/src/parse/subpacket.rs index b970319b..e96f3add 100644 --- a/openpgp/src/parse/subpacket.rs +++ b/openpgp/src/parse/subpacket.rs @@ -55,6 +55,7 @@ use std::cell::RefCell; use std::collections::HashMap; use std::fmt; +use time; use quickcheck::{Arbitrary, Gen}; @@ -65,6 +66,7 @@ use { Signature, Packet, Fingerprint, + Key, KeyID, }; @@ -862,6 +864,42 @@ impl Signature { } } + /// Returns whether or not the signature is expired. + /// + /// Note that [Section 5.2.3.4 of RFC 4880] states that "[[A + /// Signature Creation Time subpacket]] MUST be present in the + /// hashed area." Consequently, if such a packet does not exist, + /// but a "Signature Expiration Time" subpacket exists, we + /// conservatively treat the signature as expired, because there + /// is no way to evaluate the expiration time. + /// + /// [Section 5.2.3.4 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2.3.4 + pub fn signature_is_expired(&self) -> bool { + self.signature_is_expired_at(time::now_utc()) + } + + /// Returns whether or not the signature is expired at the given time. + /// + /// Note that [Section 5.2.3.4 of RFC 4880] states that "[[A + /// Signature Creation Time subpacket]] MUST be present in the + /// hashed area." Consequently, if such a packet does not exist, + /// but a "Signature Expiration Time" subpacket exists, we + /// conservatively treat the signature as expired, because there + /// is no way to evaluate the expiration time. + /// + /// [Section 5.2.3.4 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2.3.4 + pub fn signature_is_expired_at(&self, tm: time::Tm) -> bool { + match (self.signature_creation_time(), self.signature_expiration_time()) + { + (Some(c), Some(e)) => + ((c + e) as i64) <= tm.to_timespec().sec, + (None, Some(_)) => + true, // No creation time, treat as always expired. + (_, None) => + false, // No expiration time, does not expire. + } + } + /// Returns the value of the Exportable Certification subpacket, /// which contains whether the certification should be exported /// (i.e., whether the packet is *not* a local signature). @@ -998,6 +1036,29 @@ impl Signature { } } + /// Returns whether or not the key is expired. + /// + /// See [Section 5.2.3.6 of RFC 4880]. + /// + /// [Section 5.2.3.6 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2.3.6 + pub fn key_is_expired(&self, key: &Key) -> bool { + self.key_is_expired_at(key, time::now_utc()) + } + + /// Returns whether or not the key is expired at the given time. + /// + /// See [Section 5.2.3.6 of RFC 4880]. + /// + /// [Section 5.2.3.6 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2.3.6 + pub fn key_is_expired_at(&self, key: &Key, tm: time::Tm) -> bool { + match self.key_expiration_time() { + Some(e) => + ((key.creation_time + e) as i64) <= tm.to_timespec().sec, + None => + false, // No expiration time, does not expire. + } + } + /// Returns the value of the Preferred Symmetric Algorithms /// subpacket, which contains the list of symmetric algorithms /// that the key holder prefers, ordered according by the key @@ -1508,7 +1569,10 @@ fn subpacket_test_2() { = Message::from_file(path_to("../keys/subpackets/shaw.gpg")).unwrap(); // Test #1 - if let Some(&Packet::Signature(ref sig)) = message.children().nth(2) { + if let (Some(&Packet::PublicKey(ref key)), + Some(&Packet::Signature(ref sig))) + = (message.children().nth(0), message.children().nth(2)) + { // tag: 2, SignatureCreationTime(1515791508) } // tag: 9, KeyExpirationTime(63072000) } // tag: 11, PreferredSymmetricAlgorithms([9, 8, 7, 2]) } @@ -1534,6 +1598,9 @@ fn subpacket_test_2() { value: SubpacketValue::SignatureCreationTime(1515791508) })); + // The signature does not expire. + assert!(! sig.signature_is_expired()); + assert_eq!(sig.key_expiration_time(), Some(63072000)); assert_eq!(sig.subpacket(SubpacketTag::KeyExpirationTime), Some(Subpacket { @@ -1542,6 +1609,12 @@ fn subpacket_test_2() { value: SubpacketValue::KeyExpirationTime(63072000) })); + // Check key expiration. + assert!(! sig.key_is_expired_at(key, time::at_utc(time::Timespec::new( + key.creation_time as i64 + 63072000 - 1, 0)))); + assert!(sig.key_is_expired_at(key, time::at_utc(time::Timespec::new( + key.creation_time as i64 + 63072000, 0)))); + assert_eq!(sig.preferred_symmetric_algorithms(), Some(&[9, 8, 7, 2][..])); assert_eq!(sig.subpacket(SubpacketTag::PreferredSymmetricAlgorithms), |