2024-05-30 10:07:53 +02:00
use std ::time ::Duration ;
use openpgp ::parse ::Parse ;
use openpgp ::Cert ;
use openpgp ::Result ;
use sequoia_openpgp as openpgp ;
2024-08-15 13:38:43 +02:00
use super ::common ::STANDARD_POLICY ;
use super ::common ::Sq ;
use super ::common ::power_set ;
use super ::common ::time_as_string ;
2024-05-30 10:07:53 +02:00
#[ test ]
fn sq_key_subkey_expire ( ) -> Result < ( ) > {
2024-07-20 22:05:03 +02:00
let mut sq = Sq ::new ( ) ;
let ( cert , cert_path , _rev_path )
= sq . key_generate ( & [ ] , & [ " alice <alice@example.org> " ] ) ;
2024-05-31 13:22:27 +02:00
let fpr = cert . fingerprint ( ) . to_string ( ) ;
2024-05-30 10:07:53 +02:00
2024-07-20 22:05:03 +02:00
let updated_path = sq . scratch_file ( " updated.pgp " ) ;
let updated2_path = sq . scratch_file ( " updated2.pgp " ) ;
2024-05-30 10:07:53 +02:00
let keys = cert . keys ( ) . map ( | k | k . fingerprint ( ) ) . collect ::< Vec < _ > > ( ) ;
2024-07-20 22:05:03 +02:00
// Two days go by.
sq . tick ( 2 * 24 * 60 * 60 ) ;
2024-05-30 10:07:53 +02:00
for expiring in power_set ( & keys ) {
2024-05-31 13:22:27 +02:00
for keystore in [ false , true ] {
let cert_expiring = expiring . contains ( & cert . fingerprint ( ) ) ;
for ( i , fpr ) in keys . iter ( ) . enumerate ( ) {
eprintln! ( " {} . {} : {} expiring " ,
i , fpr ,
if expiring . contains ( & fpr ) {
" "
} else {
" NOT "
} ) ;
}
if keystore {
sq . key_import ( & cert_path ) ;
}
// Change the key to expire in one day.
let mut cmd = sq . command ( ) ;
cmd . args ( [
" key " , " subkey " , " expire " , " 1d " ,
] ) ;
if keystore {
cmd . args ( [ " --cert " , & fpr ] ) ;
} else {
2024-07-20 22:05:03 +02:00
cmd
. arg ( " --force " )
. arg ( " --cert-file " ) . arg ( & cert_path )
. arg ( " --output " ) . arg ( & updated_path ) ;
2024-05-31 13:22:27 +02:00
}
for k in expiring . iter ( ) {
cmd . args ( [ " --key " , & k . to_string ( ) ] ) ;
}
sq . run ( cmd , true ) ;
eprintln! ( " Updated keys at {} to expire in one day: \n {} " ,
sq . now_as_string ( ) ,
2024-07-20 22:05:03 +02:00
sq . inspect ( & updated_path ) ) ;
2024-05-31 13:22:27 +02:00
let updated = if keystore {
eprintln! ( " Updated certificate to expire in one day: \n {} " ,
sq . inspect ( cert . key_handle ( ) ) ) ;
sq . cert_export ( cert . key_handle ( ) )
} else {
eprintln! ( " Updated certificate to expire in one day: \n {} " ,
2024-07-20 22:05:03 +02:00
sq . inspect ( & updated_path ) ) ;
2024-05-31 13:22:27 +02:00
Cert ::from_file ( & updated_path ) . expect ( " valid cert " )
} ;
// It should be alive now.
let vc = updated . with_policy ( STANDARD_POLICY , sq . now ( ) ) . expect ( " valid " ) ;
for k in vc . keys ( ) {
assert! ( k . alive ( ) . is_ok ( ) ) ;
}
// It should be alive in 1 day minus 1 second.
let t = sq . now ( ) + Duration ::new ( 24 * 60 * 60 - 1 , 0 ) ;
eprintln! ( " Checking expiration status at {} " , time_as_string ( t . into ( ) ) ) ;
let vc = updated . with_policy ( STANDARD_POLICY , t ) . expect ( " valid " ) ;
for k in vc . keys ( ) {
assert! ( k . alive ( ) . is_ok ( ) ) ;
}
// But in exactly one day, it should be expired.
let t = sq . now ( ) + Duration ::new ( 24 * 60 * 60 , 0 ) ;
eprintln! ( " Checking expiration status at {} " , time_as_string ( t . into ( ) ) ) ;
let vc = updated . with_policy ( STANDARD_POLICY , t ) . expect ( " valid " ) ;
for k in vc . keys ( ) {
assert_eq! (
cert_expiring | | expiring . contains ( & k . fingerprint ( ) ) ,
k . alive ( ) . is_err ( ) ,
" {} is {}alive " ,
k . fingerprint ( ) ,
if k . alive ( ) . is_ok ( ) { " " } else { " NOT " } ) ;
}
// 12 hours go by. Clear the expiration time.
sq . tick ( 12 * 60 * 60 ) ;
let mut cmd = sq . command ( ) ;
cmd . args ( [ " key " , " subkey " , " expire " , " never " ] ) ;
if keystore {
cmd . args ( [ " --cert " , & fpr ] ) ;
} else {
2024-07-20 22:05:03 +02:00
cmd
. arg ( " --force " )
. arg ( " --cert-file " ) . arg ( & updated_path )
. arg ( " --output " ) . arg ( & updated2_path ) ;
2024-05-31 13:22:27 +02:00
}
for k in expiring . iter ( ) {
cmd . args ( [ " --key " , & k . to_string ( ) ] ) ;
}
sq . run ( cmd , true ) ;
let updated = if keystore {
eprintln! ( " Updated certificate at {} to never expire: \n {} " ,
sq . now_as_string ( ) ,
sq . inspect ( cert . key_handle ( ) ) ) ;
sq . cert_export ( cert . key_handle ( ) )
} else {
eprintln! ( " Updated certificate at {} to never expire: \n {} " ,
sq . now_as_string ( ) ,
2024-07-20 22:05:03 +02:00
sq . inspect ( & updated2_path ) ) ;
2024-05-31 13:22:27 +02:00
Cert ::from_file ( & updated2_path ) . expect ( " valid cert " )
} ;
// It should be alive now.
let vc = updated . with_policy ( STANDARD_POLICY , sq . now ( ) )
. expect ( " valid " ) ;
for k in vc . keys ( ) {
assert! ( k . alive ( ) . is_ok ( ) ) ;
}
// It should be alive in 1 day minus 1 second.
let t = sq . now ( ) + Duration ::new ( 24 * 60 * 60 - 1 , 0 ) ;
eprintln! ( " Checking expiration status at {} " , time_as_string ( t . into ( ) ) ) ;
let vc = updated . with_policy ( STANDARD_POLICY , t ) . expect ( " valid " ) ;
for k in vc . keys ( ) {
2024-09-16 15:34:48 +02:00
eprintln! ( " {} expires at {} " ,
k . fingerprint ( ) ,
if let Some ( t ) = k . key_expiration_time ( ) {
time_as_string ( t . into ( ) )
} else {
" never " . to_string ( )
} ) ;
if let Err ( err ) = k . alive ( ) {
panic! ( " {} should be alive, but it's not: {} " ,
k . fingerprint ( ) , err ) ;
}
2024-05-31 13:22:27 +02:00
}
// And in exactly one day...
let t = sq . now ( ) + Duration ::new ( 24 * 60 * 60 , 0 ) ;
eprintln! ( " Checking expiration status at {} " , time_as_string ( t . into ( ) ) ) ;
let vc = updated . with_policy ( STANDARD_POLICY , t ) . expect ( " valid " ) ;
for k in vc . keys ( ) {
2024-09-16 15:34:48 +02:00
eprintln! ( " {} expires at {} " ,
k . fingerprint ( ) ,
if let Some ( t ) = k . key_expiration_time ( ) {
time_as_string ( t . into ( ) )
} else {
" never " . to_string ( )
} ) ;
if let Err ( err ) = k . alive ( ) {
panic! ( " {} should be alive, but it's not: {} " ,
k . fingerprint ( ) , err ) ;
}
2024-05-31 13:22:27 +02:00
}
2024-05-30 10:07:53 +02:00
}
}
Ok ( ( ) )
}