summaryrefslogtreecommitdiffstats
path: root/sqv
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2019-12-13 14:25:32 +0100
committerJustus Winter <justus@sequoia-pgp.org>2019-12-13 20:57:51 +0100
commitd84d1c3fa460f814f400ffed42897601da525e69 (patch)
treec4597230f00411ae243c8f11b25901b8a8f3436a /sqv
parentc11e74020f374888caf9be63ec300bcbd1ff24b0 (diff)
sqv: Improve tests.
- Test all kinds of revocations, test signature that predates the primary key. Same with a subkey.
Diffstat (limited to 'sqv')
-rw-r--r--sqv/tests/data/revoked-key-cert-not-revoked.pgpbin0 -> 846 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-compromised.pgpbin0 -> 1001 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-compromised.sk.pgpbin0 -> 1001 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-key_retired.pgpbin0 -> 1001 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-key_retired.sk.pgpbin0 -> 1001 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-no_subpacket.pgpbin0 -> 965 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-no_subpacket.sk.pgpbin0 -> 965 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-private.pgpbin0 -> 1010 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-private.sk.pgpbin0 -> 1010 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-superseded.pgpbin0 -> 985 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-superseded.sk.pgpbin0 -> 985 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-uid_retired.pgpbin0 -> 1006 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-uid_retired.sk.pgpbin0 -> 1006 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-unknown.pgpbin0 -> 997 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-unknown.sk.pgpbin0 -> 997 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-unspecified.pgpbin0 -> 987 bytes
-rw-r--r--sqv/tests/data/revoked-key-cert-revoked-unspecified.sk.pgpbin0 -> 987 bytes
-rw-r--r--sqv/tests/data/revoked-key-keyring.pgpbin440 -> 0 bytes
-rw-r--r--sqv/tests/data/revoked-key-sig-t0.pgpbin0 -> 119 bytes
-rw-r--r--sqv/tests/data/revoked-key-sig-t0.sk.pgpbin0 -> 119 bytes
-rw-r--r--sqv/tests/data/revoked-key-sig-t1-t2.pgpbin119 -> 119 bytes
-rw-r--r--sqv/tests/data/revoked-key-sig-t1-t2.sk.pgpbin0 -> 119 bytes
-rw-r--r--sqv/tests/data/revoked-key-sig-t2-t3.pgpbin119 -> 119 bytes
-rw-r--r--sqv/tests/data/revoked-key-sig-t2-t3.sk.pgpbin0 -> 119 bytes
-rw-r--r--sqv/tests/data/revoked-key-sig-t3-now.pgpbin119 -> 119 bytes
-rw-r--r--sqv/tests/data/revoked-key-sig-t3-now.sk.pgpbin0 -> 119 bytes
-rw-r--r--sqv/tests/revoked-key.rs467
27 files changed, 402 insertions, 65 deletions
diff --git a/sqv/tests/data/revoked-key-cert-not-revoked.pgp b/sqv/tests/data/revoked-key-cert-not-revoked.pgp
new file mode 100644
index 00000000..b54bd712
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-not-revoked.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-compromised.pgp b/sqv/tests/data/revoked-key-cert-revoked-compromised.pgp
new file mode 100644
index 00000000..97ddd18e
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-compromised.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-compromised.sk.pgp b/sqv/tests/data/revoked-key-cert-revoked-compromised.sk.pgp
new file mode 100644
index 00000000..ad6cf793
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-compromised.sk.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-key_retired.pgp b/sqv/tests/data/revoked-key-cert-revoked-key_retired.pgp
new file mode 100644
index 00000000..f16ab029
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-key_retired.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-key_retired.sk.pgp b/sqv/tests/data/revoked-key-cert-revoked-key_retired.sk.pgp
new file mode 100644
index 00000000..95762735
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-key_retired.sk.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-no_subpacket.pgp b/sqv/tests/data/revoked-key-cert-revoked-no_subpacket.pgp
new file mode 100644
index 00000000..d7c2ecc5
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-no_subpacket.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-no_subpacket.sk.pgp b/sqv/tests/data/revoked-key-cert-revoked-no_subpacket.sk.pgp
new file mode 100644
index 00000000..9c554046
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-no_subpacket.sk.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-private.pgp b/sqv/tests/data/revoked-key-cert-revoked-private.pgp
new file mode 100644
index 00000000..9fc6568c
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-private.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-private.sk.pgp b/sqv/tests/data/revoked-key-cert-revoked-private.sk.pgp
new file mode 100644
index 00000000..528732ec
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-private.sk.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-superseded.pgp b/sqv/tests/data/revoked-key-cert-revoked-superseded.pgp
new file mode 100644
index 00000000..b9debcf9
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-superseded.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-superseded.sk.pgp b/sqv/tests/data/revoked-key-cert-revoked-superseded.sk.pgp
new file mode 100644
index 00000000..cae4e042
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-superseded.sk.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-uid_retired.pgp b/sqv/tests/data/revoked-key-cert-revoked-uid_retired.pgp
new file mode 100644
index 00000000..f54fe768
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-uid_retired.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-uid_retired.sk.pgp b/sqv/tests/data/revoked-key-cert-revoked-uid_retired.sk.pgp
new file mode 100644
index 00000000..910e89fc
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-uid_retired.sk.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-unknown.pgp b/sqv/tests/data/revoked-key-cert-revoked-unknown.pgp
new file mode 100644
index 00000000..3f896d7a
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-unknown.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-unknown.sk.pgp b/sqv/tests/data/revoked-key-cert-revoked-unknown.sk.pgp
new file mode 100644
index 00000000..9950548b
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-unknown.sk.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-unspecified.pgp b/sqv/tests/data/revoked-key-cert-revoked-unspecified.pgp
new file mode 100644
index 00000000..2c5e53df
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-unspecified.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-cert-revoked-unspecified.sk.pgp b/sqv/tests/data/revoked-key-cert-revoked-unspecified.sk.pgp
new file mode 100644
index 00000000..358eaf65
--- /dev/null
+++ b/sqv/tests/data/revoked-key-cert-revoked-unspecified.sk.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-keyring.pgp b/sqv/tests/data/revoked-key-keyring.pgp
deleted file mode 100644
index 6c49e422..00000000
--- a/sqv/tests/data/revoked-key-keyring.pgp
+++ /dev/null
Binary files differ
diff --git a/sqv/tests/data/revoked-key-sig-t0.pgp b/sqv/tests/data/revoked-key-sig-t0.pgp
new file mode 100644
index 00000000..a2d5d733
--- /dev/null
+++ b/sqv/tests/data/revoked-key-sig-t0.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-sig-t0.sk.pgp b/sqv/tests/data/revoked-key-sig-t0.sk.pgp
new file mode 100644
index 00000000..83dcea08
--- /dev/null
+++ b/sqv/tests/data/revoked-key-sig-t0.sk.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-sig-t1-t2.pgp b/sqv/tests/data/revoked-key-sig-t1-t2.pgp
index 4e9135bb..63ed6170 100644
--- a/sqv/tests/data/revoked-key-sig-t1-t2.pgp
+++ b/sqv/tests/data/revoked-key-sig-t1-t2.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-sig-t1-t2.sk.pgp b/sqv/tests/data/revoked-key-sig-t1-t2.sk.pgp
new file mode 100644
index 00000000..2f81ca3d
--- /dev/null
+++ b/sqv/tests/data/revoked-key-sig-t1-t2.sk.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-sig-t2-t3.pgp b/sqv/tests/data/revoked-key-sig-t2-t3.pgp
index e1476136..2e2f5611 100644
--- a/sqv/tests/data/revoked-key-sig-t2-t3.pgp
+++ b/sqv/tests/data/revoked-key-sig-t2-t3.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-sig-t2-t3.sk.pgp b/sqv/tests/data/revoked-key-sig-t2-t3.sk.pgp
new file mode 100644
index 00000000..1b42061d
--- /dev/null
+++ b/sqv/tests/data/revoked-key-sig-t2-t3.sk.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-sig-t3-now.pgp b/sqv/tests/data/revoked-key-sig-t3-now.pgp
index 9946a51e..e3541c6e 100644
--- a/sqv/tests/data/revoked-key-sig-t3-now.pgp
+++ b/sqv/tests/data/revoked-key-sig-t3-now.pgp
Binary files differ
diff --git a/sqv/tests/data/revoked-key-sig-t3-now.sk.pgp b/sqv/tests/data/revoked-key-sig-t3-now.sk.pgp
new file mode 100644
index 00000000..338af8b1
--- /dev/null
+++ b/sqv/tests/data/revoked-key-sig-t3-now.sk.pgp
Binary files differ
diff --git a/sqv/tests/revoked-key.rs b/sqv/tests/revoked-key.rs
index bc1748cf..fdfe24b5 100644
--- a/sqv/tests/revoked-key.rs
+++ b/sqv/tests/revoked-key.rs
@@ -1,3 +1,43 @@
+//! Tests revocations and binding signatures over time.
+//!
+//! These tests create a certificate with a signing capable primary
+//! key (subkey), and revoke it later on, then re-legitimize it using
+//! a new signature. We then ask sqv to verify a signature at
+//! different points in time. Hard revocations of the key invalidate
+//! the signature at any point in time, whereas in the case of soft
+//! revocations, the keys can be re-legitimized.
+//!
+//! All tests are run in three flavors:
+//!
+//! 0. The primary key makes the signatures and is revoked.
+//! 1. The subkey makes the signatures, primary key is revoked.
+//! 2. The subkey makes the signatures and is revoked.
+//!
+//! As extra subtlety, we bind the subkey *after* the t1-t2 signature.
+//!
+//! Timeline: v
+//! |
+//! t0 -| - Signature revoked-key-sig-t0.pgp
+//! |
+//! t1 -| - Primary key creation
+//! |
+//! | - Subkey creation
+//! |
+//! | - Signature revoked-key-sig-t1-t2.pgp
+//! |
+//! | - Subkey is bound
+//! |
+//! t2 -| - Revocation of (sub)key
+//! |
+//! | - Signature revoked-key-sig-t2-t3.pgp
+//! |
+//! t3 -| - New direct/binding signature
+//! |
+//! | - Signature revoked-key-sig-t3-now.pgp
+//! |
+//! now -|
+//! v
+
extern crate assert_cli;
#[cfg(test)]
@@ -5,48 +45,204 @@ mod integration {
use assert_cli::Assert;
use std::path;
- #[test]
- fn not_valid_at_signature_ctime() {
- // A hard revocation is never ignored.
+ fn sqv(keyring: &str, sig: &str) -> Assert {
Assert::cargo_binary("sqv")
.current_dir(path::Path::new("tests").join("data"))
.with_args(
- &["--keyring",
- &"revoked-key-keyring.pgp",
- &"revoked-key-sig-t1-t2.pgp",
- &"msg.txt"])
- .fails()
- .and().stderr().contains("revoked")
- .unwrap();
+ &["--trace",
+ "--keyring",
+ &format!("revoked-key-cert-{}.pgp", keyring),
+ &format!("revoked-key-sig-{}.pgp", sig),
+ "msg.txt"])
+ }
+
+ /// Tests flavor 0, primary key signs and is revoked.
+ fn f0(keyring: &str, sig: &str) -> Assert {
+ sqv(keyring, sig)
+ }
+
+ /// Tests flavor 1, subkey signs and primary key is revoked.
+ fn f1(keyring: &str, sig: &str) -> Assert {
+ sqv(keyring, &format!("{}.sk", sig))
}
+ /// Tests flavor 2, subkey signs and is revoked.
+ fn f2(keyring: &str, sig: &str) -> Assert {
+ sqv(&format!("{}.sk", keyring), &format!("{}.sk", sig))
+ }
+
+ /// Base case, cert is not revoked.
#[test]
- fn revoked_at_signature_ctime() {
- Assert::cargo_binary("sqv")
- .current_dir(path::Path::new("tests").join("data"))
- .with_args(
- &["--keyring",
- &"revoked-key-keyring.pgp",
- &"revoked-key-sig-t2-t3.pgp",
- &"msg.txt"])
- .fails()
- .and().stderr().contains("revoked")
- .unwrap();
+ fn not_revoked() {
+ let c = "not-revoked";
+ f0(c, "t0").fails().and().stderr().contains("predates").unwrap();
+ f0(c, "t1-t2").unwrap();
+ f0(c, "t2-t3").unwrap();
+ f0(c, "t3-now").unwrap();
+
+ f1(c, "t0").fails().and().stderr().contains("predates").unwrap();
+ f1(c, "t1-t2").fails().unwrap();
+ f1(c, "t2-t3").unwrap();
+ f1(c, "t3-now").unwrap();
+
+ // f2 is not used here, because we don't have any revocations.
}
+ /// The hard revocation reasons. All signatures are invalid.
#[test]
- fn unrevoked() {
- // Hard revocations are never ignored.
- Assert::cargo_binary("sqv")
- .current_dir(path::Path::new("tests").join("data"))
- .with_args(
- &["--keyring",
- &"revoked-key-keyring.pgp",
- &"revoked-key-sig-t3-now.pgp",
- &"msg.txt"])
- .fails()
- .and().stderr().contains("revoked")
- .unwrap();
+ fn revoked_no_subpacket() {
+ let c = "revoked-no_subpacket";
+ f0(c, "t0").fails().unwrap();
+ f0(c, "t1-t2").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+
+ f1(c, "t0").fails().unwrap();
+ f1(c, "t1-t2").fails().unwrap();
+ f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f1(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+
+ f2(c, "t0").fails().unwrap();
+ f2(c, "t1-t2").fails().unwrap();
+ f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f2(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+ }
+
+ #[test]
+ fn revoked_unspecified() {
+ let c = "revoked-unspecified";
+ f0(c, "t0").fails().unwrap();
+ f0(c, "t1-t2").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+
+ f1(c, "t0").fails().unwrap();
+ f1(c, "t1-t2").fails().unwrap();
+ f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f1(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+
+ f2(c, "t0").fails().unwrap();
+ f2(c, "t1-t2").fails().unwrap();
+ f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f2(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+ }
+
+ #[test]
+ fn revoked_compromised() {
+ let c = "revoked-compromised";
+ f0(c, "t0").fails().unwrap();
+ f0(c, "t1-t2").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+
+ f1(c, "t0").fails().unwrap();
+ f1(c, "t1-t2").fails().unwrap();
+ f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f1(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+
+ f2(c, "t0").fails().unwrap();
+ f2(c, "t1-t2").fails().unwrap();
+ f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f2(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+ }
+
+ #[test]
+ fn revoked_private() {
+ let c = "revoked-private";
+ f0(c, "t0").fails().unwrap();
+ f0(c, "t1-t2").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+
+ f1(c, "t0").fails().unwrap();
+ f1(c, "t1-t2").fails().unwrap();
+ f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f1(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+
+ f2(c, "t0").fails().unwrap();
+ f2(c, "t1-t2").fails().unwrap();
+ f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f2(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+ }
+
+ #[test]
+ fn revoked_unknown() {
+ let c = "revoked-unknown";
+ f0(c, "t0").fails().unwrap();
+ f0(c, "t1-t2").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+
+ f1(c, "t0").fails().unwrap();
+ f1(c, "t1-t2").fails().unwrap();
+ f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f1(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+
+ f2(c, "t0").fails().unwrap();
+ f2(c, "t1-t2").fails().unwrap();
+ f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f2(c, "t3-now").fails().and().stderr().contains("revoked").unwrap();
+ }
+
+ /// The soft revocation reasons. Only the signature dated prior
+ /// to the key creation and the one directly after the revocation
+ /// are invalid.
+ #[test]
+ fn revoked_superseded() {
+ let c = "revoked-superseded";
+ f0(c, "t0").fails().and().stderr().contains("predates").unwrap();
+ f0(c, "t1-t2").unwrap();
+ f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t3-now").unwrap();
+
+ f1(c, "t0").fails().and().stderr().contains("predates").unwrap();
+ f1(c, "t1-t2").fails().unwrap();
+ f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f1(c, "t3-now").unwrap();
+
+ f2(c, "t0").fails().and().stderr().contains("predates").unwrap();
+ f2(c, "t1-t2").fails().unwrap();
+ f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f2(c, "t3-now").unwrap();
+ }
+
+ #[test]
+ fn revoked_key_retired() {
+ let c = "revoked-key_retired";
+ f0(c, "t0").fails().and().stderr().contains("predates").unwrap();
+ f0(c, "t1-t2").unwrap();
+ f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t3-now").unwrap();
+
+ f1(c, "t0").fails().and().stderr().contains("predates").unwrap();
+ f1(c, "t1-t2").fails().unwrap();
+ f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f1(c, "t3-now").unwrap();
+
+ f2(c, "t0").fails().and().stderr().contains("predates").unwrap();
+ f2(c, "t1-t2").fails().unwrap();
+ f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f2(c, "t3-now").unwrap();
+ }
+
+ /// XXX: This is an odd one.
+ #[test]
+ fn revoked_uid_retired() {
+ let c = "revoked-uid_retired";
+ f0(c, "t0").fails().and().stderr().contains("predates").unwrap();
+ f0(c, "t1-t2").unwrap();
+ f0(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f0(c, "t3-now").unwrap();
+
+ f1(c, "t0").fails().and().stderr().contains("predates").unwrap();
+ f1(c, "t1-t2").fails().unwrap();
+ f1(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f1(c, "t3-now").unwrap();
+
+ f2(c, "t0").fails().and().stderr().contains("predates").unwrap();
+ f2(c, "t1-t2").fails().unwrap();
+ f2(c, "t2-t3").fails().and().stderr().contains("revoked").unwrap();
+ f2(c, "t3-now").unwrap();
}
}
@@ -65,6 +261,7 @@ fn create_key() {
key::{
Key4,
PrimaryRole,
+ SubordinateRole,
},
},
serialize::Serialize,
@@ -74,55 +271,181 @@ fn create_key() {
KeyFlags,
SignatureType,
HashAlgorithm,
+ ReasonForRevocation,
}
};
use chrono::offset::TimeZone;
let msg = b"Hello, World";
+ let t0 = chrono::offset::Utc.timestamp(915145200, 0); // 1999-01-01
let t1 = chrono::offset::Utc.timestamp(946681200, 0); // 2000-01-01
let t2 = chrono::offset::Utc.timestamp(978303600, 0); // 2001-01-01
let t3 = chrono::offset::Utc.timestamp(1009839600, 0); // 2002-01-01
let f1: f32 = 0.4; // Chosen by fair dice roll.
let f2: f32 = 0.7; // Likewise.
let t12 = t1 + chrono::Duration::days((300.0 * f1) as i64);
+ let t_sk_binding = t12 + chrono::Duration::days(1);
let t23 = t2 + chrono::Duration::days((300.0 * f2) as i64);
+
+ // Create primary key.
let mut key: Key<_, PrimaryRole> =
Key4::generate_ecc(true, Curve::Ed25519).unwrap().into();
key.set_creation_time(t1).unwrap();
let mut signer = key.clone().into_keypair().unwrap();
- // 1st binding sig valid from t1 on
+ // Create subkey.
+ let mut subkey: Key<_, SubordinateRole> =
+ Key4::generate_ecc(true, Curve::Ed25519).unwrap().into();
+ subkey.set_creation_time(t1 + chrono::Duration::days(1)).unwrap();
+ let mut sk_signer = subkey.clone().into_keypair().unwrap();
+
+ // 1st direct key signature valid from t1 on
let mut b = signature::Builder::new(SignatureType::DirectKey)
.set_features(&Features::sequoia()).unwrap()
- .set_key_flags(&KeyFlags::default().set_signing(true)).unwrap()
+ .set_key_flags(&KeyFlags::default()
+ .set_signing(true).set_certification(true)).unwrap()
.set_signature_creation_time(t1).unwrap()
- .set_key_expiration_time(Some(std::time::Duration::new(
- 20 * 52 * 7 * 24 * 60 * 60, 0))).unwrap()
.set_issuer_fingerprint(key.fingerprint()).unwrap()
.set_issuer(key.fingerprint().into()).unwrap()
.set_preferred_hash_algorithms(vec![HashAlgorithm::SHA512])
.unwrap();
- let bind1 = b.sign_primary_key_binding(&mut signer).unwrap();
+ let direct1 = b.sign_primary_key_binding(&mut signer).unwrap();
- // Revocation sig valid from t2 on
- b = signature::Builder::new(SignatureType::KeyRevocation)
- .set_signature_creation_time(t2).unwrap()
+ // 1st subkey binding signature valid from t_sk_binding on
+ b = signature::Builder::new(SignatureType::SubkeyBinding)
+ .set_key_flags(&KeyFlags::default().set_signing(true)).unwrap()
+ .set_signature_creation_time(t_sk_binding).unwrap()
.set_issuer_fingerprint(key.fingerprint()).unwrap()
- .set_issuer(key.fingerprint().into()).unwrap();
- let rev = b.sign_primary_key_binding(&mut signer).unwrap();
+ .set_issuer(key.fingerprint().into()).unwrap()
+ .set_embedded_signature(
+ signature::Builder::new(SignatureType::PrimaryKeyBinding)
+ .set_signature_creation_time(t_sk_binding).unwrap()
+ .set_issuer_fingerprint(subkey.fingerprint()).unwrap()
+ .set_issuer(subkey.keyid()).unwrap()
+ .sign_subkey_binding(&mut sk_signer, &key, &subkey).unwrap())
+ .unwrap();
+ let sk_bind1 = b.sign_subkey_binding(&mut signer, &key, &subkey).unwrap();
- // 2nd binding sig valid from t3 on
+ // 2nd direct key signature valid from t3 on
b = signature::Builder::new(SignatureType::DirectKey)
.set_features(&Features::sequoia()).unwrap()
- .set_key_flags(&KeyFlags::default().set_signing(true)).unwrap()
+ .set_key_flags(&KeyFlags::default()
+ .set_signing(true).set_certification(true)).unwrap()
.set_signature_creation_time(t3).unwrap()
- .set_key_expiration_time(Some(std::time::Duration::new(
- 20 * 52 * 7 * 24 * 60 * 60, 0))).unwrap()
.set_issuer_fingerprint(key.fingerprint()).unwrap()
.set_issuer(key.fingerprint().into()).unwrap()
.set_preferred_hash_algorithms(vec![HashAlgorithm::SHA512])
.unwrap();
- let bind2 = b.sign_primary_key_binding(&mut signer).unwrap();
+ let direct2 = b.sign_primary_key_binding(&mut signer).unwrap();
+
+ // 2nd subkey binding signature valid from t3 on
+ let mut b = signature::Builder::new(SignatureType::SubkeyBinding)
+ .set_key_flags(&KeyFlags::default().set_signing(true)).unwrap()
+ .set_signature_creation_time(t3).unwrap()
+ .set_issuer_fingerprint(key.fingerprint()).unwrap()
+ .set_issuer(key.fingerprint().into()).unwrap()
+ .set_embedded_signature(
+ signature::Builder::new(SignatureType::PrimaryKeyBinding)
+ .set_signature_creation_time(t3).unwrap()
+ .set_issuer_fingerprint(subkey.fingerprint()).unwrap()
+ .set_issuer(subkey.keyid()).unwrap()
+ .sign_subkey_binding(&mut sk_signer, &key, &subkey).unwrap())
+ .unwrap();
+ let sk_bind2 = b.sign_subkey_binding(&mut signer, &key, &subkey).unwrap();
+
+ let cert = Cert::from_packet_pile(PacketPile::from(vec![
+ key.clone().into(),
+ direct1.clone().into(),
+ direct2.clone().into(),
+ subkey.clone().into(),
+ sk_bind1.clone().into(),
+ sk_bind2.clone().into(),
+ ])).unwrap();
+ let mut fd = File::create("revoked-key-cert-not-revoked.pgp").unwrap();
+ cert.serialize(&mut fd).unwrap();
+
+ for (slug, reason) in &[
+ ("no_subpacket", None),
+ ("unspecified", Some(ReasonForRevocation::Unspecified)),
+ ("superseded", Some(ReasonForRevocation::KeySuperseded)),
+ ("compromised", Some(ReasonForRevocation::KeyCompromised)),
+ ("key_retired", Some(ReasonForRevocation::KeyRetired)),
+ ("uid_retired", Some(ReasonForRevocation::UIDRetired)),
+ ("private", Some(ReasonForRevocation::Private(100))),
+ ("unknown", Some(ReasonForRevocation::Unknown(200))),
+ ] {
+ // Revocation sig valid from t2 on
+ let mut b = signature::Builder::new(SignatureType::KeyRevocation)
+ .set_signature_creation_time(t2).unwrap()
+ .set_issuer_fingerprint(key.fingerprint()).unwrap()
+ .set_issuer(key.fingerprint().into()).unwrap();
+
+ if let Some(r) = reason {
+ b = b.set_reason_for_revocation(r.clone(), r.to_string().as_bytes())
+ .unwrap();
+ }
+
+ let rev = b.sign_primary_key_binding(&mut signer).unwrap();
+ let cert = Cert::from_packet_pile(PacketPile::from(vec![
+ key.clone(