Add a global option, --policy-as-of, to select a crypto policy.

- When working with older messages, it may be necessary to use a
    different cryptographic policy.  Add an option, `--policy-as-of`, to
    select the cryptographic policy that was in effect at the specified
    time.

  - Fixes #123.

Co-authored-by: Neal H. Walfield <neal@sequoia-pgp.org>
This commit is contained in:
Jens Reimann 2023-06-07 10:53:46 +02:00 committed by Neal H. Walfield
parent 0889d18da7
commit 4f73627020
No known key found for this signature in database
GPG Key ID: 6863C9AD5B4D22D3
8 changed files with 236 additions and 6 deletions

2
NEWS
View File

@ -8,6 +8,8 @@
certificates.
- `sq verify` now deletes the output file on failure.
- `sq decrypt` now deletes the output file on failure.
- Add a global option, `--policy-as-of`, that selects the
cryptographic policy as of the specified time.
* Changes in 0.39.0
** Notable changes

View File

@ -382,10 +382,11 @@ store, and the results are merged together."
)]
// TODO is this the right type?
pub known_notation: Vec<String>,
#[clap(
long = "time",
value_name = "TIME",
help = "Set the reference time as ISO 8601 formatted timestamp",
help = "Set the reference time as an ISO 8601 formatted timestamp",
global = true,
help_heading = GLOBAL_OPTIONS_HEADER,
long_help = "\
@ -409,6 +410,34 @@ $ sq --time 20130721T0550+0200 verify msg.pgp
",
)]
pub time: Option<types::Time>,
#[clap(
long = "policy-as-of",
value_name = "TIME",
help = "Select the cryptographic policy as of the specified time",
global = true,
help_heading = GLOBAL_OPTIONS_HEADER,
long_help = "\
Select the cryptographic policy as of the specified time, which is \
expressed as an ISO 8601 formatted timestamp. The policy determines \
what cryptographic constructs are allowed.
If you are working with a message that sq rejects, because it is \
protected by cryptographic constructs that are now considered broken, \
you can use this option to select a different cryptographic policy. \
If you are relying on the cryptography, e.g., you are verifying a \
signature, then you should only do this if you are confident that the \
message hasn't been tampered with.
TIME is interpreted as an ISO 8601 timestamp. To set the \
policy time to January 1, 2007 at midnight UTC, you can do:
$ sq --policy-as-of 20070101 verify msg.pgp
Defaults to the reference time, which can be set using --time.
",
)]
pub policy_as_of: Option<types::Time>,
#[clap(
long = "trust-root",
value_name = "FINGERPRINT|KEYID",

View File

@ -197,12 +197,12 @@ pub fn lint(mut sq: Sq, args: Command) -> Result<()> {
// Standard policy that unconditionally rejects SHA-1: this is
// where we want to be.
let mut sp = StandardPolicy::new();
let mut sp = StandardPolicy::at(sq.policy_as_of);
sp.reject_hash(HashAlgorithm::SHA1);
let sp = &sp;
// A standard policy that also accepts SHA-1.
let mut sp_sha1 = StandardPolicy::new();
let mut sp_sha1 = StandardPolicy::at(sq.policy_as_of);
sp_sha1.accept_hash(HashAlgorithm::SHA1);
let sp_sha1 = &sp_sha1;

View File

@ -206,7 +206,13 @@ fn real_main() -> Result<()> {
let time: SystemTime =
c.time.clone().unwrap_or_else(|| Time::now()).into();
let mut policy = sequoia_policy_config::ConfiguredStandardPolicy::new();
let policy_as_of = c.policy_as_of.clone()
.map(|t| SystemTime::from(t)).unwrap_or_else(|| {
time.clone()
});
let mut policy
= sequoia_policy_config::ConfiguredStandardPolicy::at(policy_as_of);
policy.parse_default_config()?;
let mut policy = policy.build();
@ -231,9 +237,10 @@ fn real_main() -> Result<()> {
quiet: c.quiet,
overwrite: c.overwrite,
batch: c.batch,
policy: &policy,
time,
time_is_now,
policy_as_of,
policy: &policy,
home: if let Some(p) = c.home.as_ref().and_then(|a| a.path()) {
sequoia_directories::Home::new(p)?
} else {

View File

@ -95,9 +95,10 @@ pub struct Sq<'store, 'rstore>
/// Prevent any kind of interactive prompting.
pub batch: bool,
pub policy: &'rstore P<'rstore>,
pub time: SystemTime,
pub time_is_now: bool,
pub policy: &'rstore P<'rstore>,
pub policy_as_of: SystemTime,
pub home: sequoia_directories::Home,
// --no-cert-store
pub no_rw_cert_store: bool,

View File

@ -0,0 +1,120 @@
-----BEGIN PGP MESSAGE-----
xA0DAAoBa4eC1VsZ6TIBy9NsYgAAAAAAQSBDeXBoZXJwdW5rJ3MgTWFuaWZlc3Rv
CmJ5IEVyaWMgSHVnaGVzCgpQcml2YWN5IGlzIG5lY2Vzc2FyeSBmb3IgYW4gb3Bl
biBzb2NpZXR5IGluIHRoZSBlbGVjdHJvbmljCmFnZS4gUHJpdmFjeSBpcyBub3Qg
c2VjcmVjeS4gQSBwcml2YXRlIG1hdHRlciBpcyBzb21ldGhpbmcgb25lIGRvZXNu
J3QKd2FudCB0aGUgd2hvbGUgd29ybGQgdG8ga25vdywgYnV0IGEgc2VjcmV0IG1h
dHRlciBpcyBzb21ldGhpbmcgb25lCmRvZXNuJ3Qgd2FudCBhbnlib2R5IHRvIGtu
b3cuIFByaXZhY3kgaXMgdGhlIHBvd2VyIHRvIHNlbGVjdGl2ZWx5CnJldmVhbCBv
bmVzZWxmIHRvIHRoZSB3b3JsZC4KCklmIHR3byBwYXJ0aWVzIGhhdmUgc29tZSBz
b3J0IG9mIGRlYWxpbmdzLCB0aGVuIGVhY2ggaGFzIGEgbWVtb3J5IG9mCnRoZWly
IGludGVyYWN0aW9uLiBFYWNoIHBhcnR5IGNhbiBzcGVhayBhYm91dCB0aGVpciBv
d24gbWVtb3J5IG9mCnRoaXM7IGhvdyBjb3VsZCBhbnlvbmUgcHJldmVudCBpdD8g
T25lIGNvdWxkIHBhc3MgbGF3cyBhZ2FpbnN0IGl0LCBidXQKdGhlIGZyZWVkb20g
b2Ygc3BlZWNoLCBldmVuIG1vcmUgdGhhbiBwcml2YWN5LCBpcyBmdW5kYW1lbnRh
bCB0byBhbgpvcGVuIHNvY2lldHk7IHdlIHNlZWsgbm90IHRvIHJlc3RyaWN0IGFu
eSBzcGVlY2ggYXQgYWxsLiBJZiBtYW55CnBhcnRpZXMgc3BlYWsgdG9nZXRoZXIg
aW4gdGhlIHNhbWUgZm9ydW0sIGVhY2ggY2FuIHNwZWFrIHRvIGFsbCB0aGUKb3Ro
ZXJzIGFuZCBhZ2dyZWdhdGUgdG9nZXRoZXIga25vd2xlZGdlIGFib3V0IGluZGl2
aWR1YWxzIGFuZCBvdGhlcgpwYXJ0aWVzLiBUaGUgcG93ZXIgb2YgZWxlY3Ryb25p
YyBjb21tdW5pY2F0aW9ucyBoYXMgZW5hYmxlZCBzdWNoIGdyb3VwCnNwZWVjaCwg
YW5kIGl0IHdpbGwgbm90IGdvIGF3YXkgbWVyZWx5IGJlY2F1c2Ugd2UgbWlnaHQg
d2FudCBpdCB0by4KClNpbmNlIHdlIGRlc2lyZSBwcml2YWN5LCB3ZSBtdXN0IGVu
c3VyZSB0aGF0IGVhY2ggcGFydHkgdG8gYQp0cmFuc2FjdGlvbiBoYXZlIGtub3ds
ZWRnZSBvbmx5IG9mIHRoYXQgd2hpY2ggaXMgZGlyZWN0bHkgbmVjZXNzYXJ5CmZv
ciB0aGF0IHRyYW5zYWN0aW9uLiBTaW5jZSBhbnkgaW5mb3JtYXRpb24gY2FuIGJl
IHNwb2tlbiBvZiwgd2UgbXVzdAplbnN1cmUgdGhhdCB3ZSByZXZlYWwgYXMgbGl0
dGxlIGFzIHBvc3NpYmxlLiBJbiBtb3N0IGNhc2VzIHBlcnNvbmFsCmlkZW50aXR5
IGlzIG5vdCBzYWxpZW50LiBXaGVuIEkgcHVyY2hhc2UgYSBtYWdhemluZSBhdCBh
IHN0b3JlIGFuZApoYW5kIGNhc2ggdG8gdGhlIGNsZXJrLCB0aGVyZSBpcyBubyBu
ZWVkIHRvIGtub3cgd2hvIEkgYW0uIFdoZW4gSSBhc2sKbXkgZWxlY3Ryb25pYyBt
YWlsIHByb3ZpZGVyIHRvIHNlbmQgYW5kIHJlY2VpdmUgbWVzc2FnZXMsIG15IHBy
b3ZpZGVyCm5lZWQgbm90IGtub3cgdG8gd2hvbSBJIGFtIHNwZWFraW5nIG9yIHdo
YXQgSSBhbSBzYXlpbmcgb3Igd2hhdCBvdGhlcnMKYXJlIHNheWluZyB0byBtZTsg
bXkgcHJvdmlkZXIgb25seSBuZWVkIGtub3cgaG93IHRvIGdldCB0aGUgbWVzc2Fn
ZQp0aGVyZSBhbmQgaG93IG11Y2ggSSBvd2UgdGhlbSBpbiBmZWVzLiBXaGVuIG15
IGlkZW50aXR5IGlzIHJldmVhbGVkIGJ5CnRoZSB1bmRlcmx5aW5nIG1lY2hhbmlz
bSBvZiB0aGUgdHJhbnNhY3Rpb24sIEkgaGF2ZSBubyBwcml2YWN5LiBJCmNhbm5v
dCBoZXJlIHNlbGVjdGl2ZWx5IHJldmVhbCBteXNlbGY7IEkgbXVzdCBhbHdheXMg
cmV2ZWFsIG15c2VsZi4KClRoZXJlZm9yZSwgcHJpdmFjeSBpbiBhbiBvcGVuIHNv
Y2lldHkgcmVxdWlyZXMgYW5vbnltb3VzIHRyYW5zYWN0aW9uCnN5c3RlbXMuIFVu
dGlsIG5vdywgY2FzaCBoYXMgYmVlbiB0aGUgcHJpbWFyeSBzdWNoIHN5c3RlbS4g
QW4KYW5vbnltb3VzIHRyYW5zYWN0aW9uIHN5c3RlbSBpcyBub3QgYSBzZWNyZXQg
dHJhbnNhY3Rpb24gc3lzdGVtLiBBbgphbm9ueW1vdXMgc3lzdGVtIGVtcG93ZXJz
IGluZGl2aWR1YWxzIHRvIHJldmVhbCB0aGVpciBpZGVudGl0eSB3aGVuCmRlc2ly
ZWQgYW5kIG9ubHkgd2hlbiBkZXNpcmVkOyB0aGlzIGlzIHRoZSBlc3NlbmNlIG9m
IHByaXZhY3kuCgpQcml2YWN5IGluIGFuIG9wZW4gc29jaWV0eSBhbHNvIHJlcXVp
cmVzIGNyeXB0b2dyYXBoeS4gSWYgSSBzYXkKc29tZXRoaW5nLCBJIHdhbnQgaXQg
aGVhcmQgb25seSBieSB0aG9zZSBmb3Igd2hvbSBJIGludGVuZCBpdC4gSWYgdGhl
CmNvbnRlbnQgb2YgbXkgc3BlZWNoIGlzIGF2YWlsYWJsZSB0byB0aGUgd29ybGQs
IEkgaGF2ZSBubyBwcml2YWN5LiBUbwplbmNyeXB0IGlzIHRvIGluZGljYXRlIHRo
ZSBkZXNpcmUgZm9yIHByaXZhY3ksIGFuZCB0byBlbmNyeXB0IHdpdGgKd2VhayBj
cnlwdG9ncmFwaHkgaXMgdG8gaW5kaWNhdGUgbm90IHRvbyBtdWNoIGRlc2lyZSBm
b3IKcHJpdmFjeS4gRnVydGhlcm1vcmUsIHRvIHJldmVhbCBvbmUncyBpZGVudGl0
eSB3aXRoIGFzc3VyYW5jZSB3aGVuIHRoZQpkZWZhdWx0IGlzIGFub255bWl0eSBy
ZXF1aXJlcyB0aGUgY3J5cHRvZ3JhcGhpYyBzaWduYXR1cmUuCgpXZSBjYW5ub3Qg
ZXhwZWN0IGdvdmVybm1lbnRzLCBjb3Jwb3JhdGlvbnMsIG9yIG90aGVyIGxhcmdl
LCBmYWNlbGVzcwpvcmdhbml6YXRpb25zIHRvIGdyYW50IHVzIHByaXZhY3kgb3V0
IG9mIHRoZWlyIGJlbmVmaWNlbmNlLiBJdCBpcyB0bwp0aGVpciBhZHZhbnRhZ2Ug
dG8gc3BlYWsgb2YgdXMsIGFuZCB3ZSBzaG91bGQgZXhwZWN0IHRoYXQgdGhleSB3
aWxsCnNwZWFrLiBUbyB0cnkgdG8gcHJldmVudCB0aGVpciBzcGVlY2ggaXMgdG8g
ZmlnaHQgYWdhaW5zdCB0aGUKcmVhbGl0aWVzIG9mIGluZm9ybWF0aW9uLiBJbmZv
cm1hdGlvbiBkb2VzIG5vdCBqdXN0IHdhbnQgdG8gYmUgZnJlZSwKaXQgbG9uZ3Mg
dG8gYmUgZnJlZS4gSW5mb3JtYXRpb24gZXhwYW5kcyB0byBmaWxsIHRoZSBhdmFp
bGFibGUgc3RvcmFnZQpzcGFjZS4gSW5mb3JtYXRpb24gaXMgUnVtb3IncyB5b3Vu
Z2VyLCBzdHJvbmdlciBjb3VzaW47IEluZm9ybWF0aW9uIGlzCmZsZWV0ZXIgb2Yg
Zm9vdCwgaGFzIG1vcmUgZXllcywga25vd3MgbW9yZSwgYW5kIHVuZGVyc3RhbmRz
IGxlc3MgdGhhbgpSdW1vci4KCldlIG11c3QgZGVmZW5kIG91ciBvd24gcHJpdmFj
eSBpZiB3ZSBleHBlY3QgdG8gaGF2ZSBhbnkuIFdlIG11c3QgY29tZQp0b2dldGhl
ciBhbmQgY3JlYXRlIHN5c3RlbXMgd2hpY2ggYWxsb3cgYW5vbnltb3VzIHRyYW5z
YWN0aW9ucyB0byB0YWtlCnBsYWNlLiBQZW9wbGUgaGF2ZSBiZWVuIGRlZmVuZGlu
ZyB0aGVpciBvd24gcHJpdmFjeSBmb3IgY2VudHVyaWVzIHdpdGgKd2hpc3BlcnMs
IGRhcmtuZXNzLCBlbnZlbG9wZXMsIGNsb3NlZCBkb29ycywgc2VjcmV0IGhhbmRz
aGFrZXMsIGFuZApjb3VyaWVycy4gVGhlIHRlY2hub2xvZ2llcyBvZiB0aGUgcGFz
dCBkaWQgbm90IGFsbG93IGZvciBzdHJvbmcKcHJpdmFjeSwgYnV0IGVsZWN0cm9u
aWMgdGVjaG5vbG9naWVzIGRvLgoKV2UgdGhlIEN5cGhlcnB1bmtzIGFyZSBkZWRp
Y2F0ZWQgdG8gYnVpbGRpbmcgYW5vbnltb3VzIHN5c3RlbXMuIFdlIGFyZQpkZWZl
bmRpbmcgb3VyIHByaXZhY3kgd2l0aCBjcnlwdG9ncmFwaHksIHdpdGggYW5vbnlt
b3VzIG1haWwKZm9yd2FyZGluZyBzeXN0ZW1zLCB3aXRoIGRpZ2l0YWwgc2lnbmF0
dXJlcywgYW5kIHdpdGggZWxlY3Ryb25pYwptb25leS4KCkN5cGhlcnB1bmtzIHdy
aXRlIGNvZGUuIFdlIGtub3cgdGhhdCBzb21lb25lIGhhcyB0byB3cml0ZSBzb2Z0
d2FyZSB0bwpkZWZlbmQgcHJpdmFjeSwgYW5kIHNpbmNlIHdlIGNhbid0IGdldCBw
cml2YWN5IHVubGVzcyB3ZSBhbGwgZG8sIHdlJ3JlCmdvaW5nIHRvIHdyaXRlIGl0
LiBXZSBwdWJsaXNoIG91ciBjb2RlIHNvIHRoYXQgb3VyIGZlbGxvdyBDeXBoZXJw
dW5rcwptYXkgcHJhY3RpY2UgYW5kIHBsYXkgd2l0aCBpdC4gT3VyIGNvZGUgaXMg
ZnJlZSBmb3IgYWxsIHRvIHVzZSwKd29ybGR3aWRlLiBXZSBkb24ndCBtdWNoIGNh
cmUgaWYgeW91IGRvbid0IGFwcHJvdmUgb2YgdGhlIHNvZnR3YXJlIHdlCndyaXRl
LiBXZSBrbm93IHRoYXQgc29mdHdhcmUgY2FuJ3QgYmUgZGVzdHJveWVkIGFuZCB0
aGF0IGEgd2lkZWx5CmRpc3BlcnNlZCBzeXN0ZW0gY2FuJ3QgYmUgc2h1dCBkb3du
LgoKQ3lwaGVycHVua3MgZGVwbG9yZSByZWd1bGF0aW9ucyBvbiBjcnlwdG9ncmFw
aHksIGZvciBlbmNyeXB0aW9uIGlzCmZ1bmRhbWVudGFsbHkgYSBwcml2YXRlIGFj
dC4gVGhlIGFjdCBvZiBlbmNyeXB0aW9uLCBpbiBmYWN0LCByZW1vdmVzCmluZm9y
bWF0aW9uIGZyb20gdGhlIHB1YmxpYyByZWFsbS4gRXZlbiBsYXdzIGFnYWluc3Qg
Y3J5cHRvZ3JhcGh5CnJlYWNoIG9ubHkgc28gZmFyIGFzIGEgbmF0aW9uJ3MgYm9y
ZGVyIGFuZCB0aGUgYXJtIG9mIGl0cwp2aW9sZW5jZS4gQ3J5cHRvZ3JhcGh5IHdp
bGwgaW5lbHVjdGFibHkgc3ByZWFkIG92ZXIgdGhlIHdob2xlIGdsb2JlLAphbmQg
d2l0aCBpdCB0aGUgYW5vbnltb3VzIHRyYW5zYWN0aW9ucyBzeXN0ZW1zIHRoYXQg
aXQgbWFrZXMgcG9zc2libGUuCgpGb3IgcHJpdmFjeSB0byBiZSB3aWRlc3ByZWFk
IGl0IG11c3QgYmUgcGFydCBvZiBhIHNvY2lhbApjb250cmFjdC4gUGVvcGxlIG11
c3QgY29tZSBhbmQgdG9nZXRoZXIgZGVwbG95IHRoZXNlIHN5c3RlbXMgZm9yIHRo
ZQpjb21tb24gZ29vZC4gUHJpdmFjeSBvbmx5IGV4dGVuZHMgc28gZmFyIGFzIHRo
ZSBjb29wZXJhdGlvbiBvZiBvbmUncwpmZWxsb3dzIGluIHNvY2lldHkuIFdlIHRo
ZSBDeXBoZXJwdW5rcyBzZWVrIHlvdXIgcXVlc3Rpb25zIGFuZCB5b3VyCmNvbmNl
cm5zIGFuZCBob3BlIHdlIG1heSBlbmdhZ2UgeW91IHNvIHRoYXQgd2UgZG8gbm90
IGRlY2VpdmUKb3Vyc2VsdmVzLiBXZSB3aWxsIG5vdCwgaG93ZXZlciwgYmUgbW92
ZWQgb3V0IG9mIG91ciBjb3Vyc2UgYmVjYXVzZQpzb21lIG1heSBkaXNhZ3JlZSB3
aXRoIG91ciBnb2Fscy4KClRoZSBDeXBoZXJwdW5rcyBhcmUgYWN0aXZlbHkgZW5n
YWdlZCBpbiBtYWtpbmcgdGhlIG5ldHdvcmtzIHNhZmVyIGZvcgpwcml2YWN5LiBM
ZXQgdXMgcHJvY2VlZCB0b2dldGhlciBhcGFjZS4KCk9ud2FyZC4KCkVyaWMgSHVn
aGVzIDxodWdoZXNAc29kYS5iZXJrZWxleS5lZHU+Cgo5IE1hcmNoIDE5OTMgCsLA
uwQAAQoAbwWCZyOIzAkQa4eC1VsZ6TJHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMu
c2VxdW9pYS1wZ3Aub3Jn67ksSK0NThSMkF367tAaCp6fSrRIZBb+Wb85mcf7jukW
IQTTj5U60eVThs5m41Zrh4LVWxnpMgAAerAIALNKx6azoS37LfLyWgr818tgVcSe
1m0JNjSiC5D9RC6thOX8qwbtRi6sZiuNN1TQBlh4eMyPAEL4TehsEJifg62vCHJG
mxhYPXAtK9sQweUs+z97WCKQboFUw+S4bpJJtrz+V5JR+myJGktTHSX7v6I1cP2S
bTCOhdcM246sWnKEqlOa0jcWkGPOmwVIjSIGZ0qDV9qcTz9fU/5g+yfnYzf5bg9d
wk26szxY5vpcWYOkDpqdbZ35hQaIHRN0nfZ6yAYC96esuw6oNWXbGl1pcT41Od0c
Kumq8KmIzjxKRzRmx34qgMzWEAmmijcwgJCh9TFQR6DVcQ0KGs/KGzlkiPY=
=kp6c
-----END PGP MESSAGE-----

View File

@ -17,6 +17,7 @@ use assert_cmd::Command;
use chrono::DateTime;
use chrono::Duration;
use chrono::TimeZone;
use chrono::Utc;
use openpgp::packet::Signature;
@ -260,6 +261,19 @@ impl Drop for Sq {
}
impl Sq {
/// Creates a new Sq context in a new, emphemeral home directory.
/// The clock is set to the specified time.
pub fn at_str(t: &str) -> Self {
if let Ok(d) = chrono::NaiveDateTime::parse_from_str(t, "%Y-%m-%dT%H:%M:%S") {
return Self::at(Utc.from_utc_datetime(&d).into());
}
if let Ok(d) = chrono::NaiveDate::parse_from_str(t, "%Y-%m-%d") {
let pad_date_with = chrono::NaiveTime::from_hms_opt(0, 0, 0).unwrap();
return Self::at(Utc.from_utc_datetime(&d.and_time(pad_date_with)).into());
}
panic!("Invalid timestamp, must be YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS");
}
/// Creates a new Sq context in a new, emphemeral home directory.
/// The clock is set to the specified time.
pub fn at(now: std::time::SystemTime) -> Self {

View File

@ -6,6 +6,7 @@ use std::io;
use sequoia_openpgp as openpgp;
use openpgp::Result;
use super::common::artifact;
use super::common::Sq;
// Make sure verifying bad data fails, and removes the intermediate
@ -72,3 +73,59 @@ fn sq_verify_bad() -> Result<()> {
Ok(())
}
// Make sure --policy-as-of works
#[test]
fn sq_verify_policy_as_of() -> Result<()> {
let sq = Sq::at_str("2024-11-01");
let cert = artifact("keys/only-sha1-pub.pgp");
let msg = artifact("messages/signed-by-only-sha1.pgp");
assert!(
sq.verify_maybe(
&[
"--signer-file", &cert.display().to_string(),
],
&msg,
None)
.is_err());
// Setting the reference time is not enough, because the message's
// creation time would be in the future.
assert!(
sq.verify_maybe(
&[
"--time", "2022-01-01",
"--signer-file", &cert.display().to_string(),
],
&msg,
None)
.is_err());
// But setting the policy time is.
assert!(
sq.verify_maybe(
&[
"--policy-as-of", "2022-01-01",
"--signer-file", &cert.display().to_string(),
],
&msg,
None)
.is_ok());
// Make sure we can set both the reference time and the policy
// time.
assert!(
sq.verify_maybe(
&[
"--time", "2025-01-01",
"--policy-as-of", "2022-01-01",
"--signer-file", &cert.display().to_string(),
],
&msg,
None)
.is_ok());
Ok(())
}