@@ -23,9 +23,6 @@ pub type ValidationResult = Result<(), ValidationError>;
2323/// Parameters to be used during validation.
2424#[ derive( Debug ) ]
2525pub struct ValidationParameters {
26- /// The timestamp to use for token temporal checks.
27- pub current_time : DateTime < Utc > ,
28-
2926 /// The maximum allowed chain length.
3027 pub max_chain_length : usize ,
3128
@@ -42,7 +39,6 @@ pub struct ValidationParameters {
4239impl Default for ValidationParameters {
4340 fn default ( ) -> Self {
4441 Self {
45- current_time : Utc :: now ( ) ,
4642 max_chain_length : MAX_CHAIN_LENGTH ,
4743 max_policy_width : MAX_POLICY_WIDTH ,
4844 max_policy_depth : MAX_POLICY_DEPTH ,
@@ -65,15 +61,17 @@ pub enum TokenTypeRequirements {
6561 None ,
6662}
6763
64+ /// A NUC validator.
6865pub struct NucValidator {
6966 root_keys : HashSet < Box < [ u8 ] > > ,
67+ time_provider : Box < dyn TimeProvider > ,
7068}
7169
7270impl NucValidator {
7371 /// Construct a new NUC validator.
7472 pub fn new ( root_keys : & [ PublicKey ] ) -> Self {
7573 let root_keys = root_keys. iter ( ) . map ( |pk| pk. to_sec1_bytes ( ) ) . collect ( ) ;
76- Self { root_keys }
74+ Self { root_keys, time_provider : Box :: new ( SystemClockTimeProvider ) }
7775 }
7876
7977 /// Validate a NUC.
@@ -97,8 +95,9 @@ impl NucValidator {
9795
9896 // Create a sequence [root, ..., token]
9997 let token_chain = iter:: once ( token) . chain ( proofs. iter ( ) . copied ( ) ) . rev ( ) ;
98+ let now = self . time_provider . current_time ( ) ;
10099 Self :: validate_proofs ( token, & proofs, & self . root_keys ) ?;
101- Self :: validate_token_chain ( token_chain, & parameters) ?;
100+ Self :: validate_token_chain ( token_chain, & parameters, now ) ?;
102101 Self :: validate_token ( token, & proofs, & parameters. token_requirements , context) ?;
103102
104103 // Signature validation is done at the end as it's arguably the most expensive part of the
@@ -171,15 +170,19 @@ impl NucValidator {
171170 }
172171
173172 // Validations applied to the entire chain (proofs + token).
174- fn validate_token_chain < ' a , I > ( mut tokens : I , parameters : & ValidationParameters ) -> Result < ( ) , ValidationError >
173+ fn validate_token_chain < ' a , I > (
174+ mut tokens : I ,
175+ parameters : & ValidationParameters ,
176+ current_time : DateTime < Utc > ,
177+ ) -> Result < ( ) , ValidationError >
175178 where
176179 I : Iterator < Item = & ' a NucToken > + Clone ,
177180 {
178181 for ( previous, current) in tokens. clone ( ) . tuple_windows ( ) {
179182 Self :: validate_relationship_properties ( previous, current) ?;
180183 }
181184 for token in tokens. clone ( ) {
182- Self :: validate_temporal_properties ( token, & parameters . current_time ) ?;
185+ Self :: validate_temporal_properties ( token, & current_time) ?;
183186 }
184187 for token in tokens. clone ( ) {
185188 if let TokenBody :: Delegation ( policies) = & token. body {
@@ -408,6 +411,18 @@ impl fmt::Display for ValidationKind {
408411 }
409412}
410413
414+ trait TimeProvider : Send + Sync + ' static {
415+ fn current_time ( & self ) -> DateTime < Utc > ;
416+ }
417+
418+ struct SystemClockTimeProvider ;
419+
420+ impl TimeProvider for SystemClockTimeProvider {
421+ fn current_time ( & self ) -> DateTime < Utc > {
422+ Utc :: now ( )
423+ }
424+ }
425+
411426#[ cfg( test) ]
412427mod tests {
413428 use super :: * ;
@@ -466,22 +481,46 @@ mod tests {
466481 }
467482 }
468483
484+ enum TimeConfig {
485+ System ,
486+ Mock ( DateTime < Utc > ) ,
487+ }
488+
489+ struct MockTimeProvider ( DateTime < Utc > ) ;
490+
491+ impl TimeProvider for MockTimeProvider {
492+ fn current_time ( & self ) -> DateTime < Utc > {
493+ self . 0
494+ }
495+ }
496+
469497 struct Asserter {
470498 parameters : ValidationParameters ,
471499 root_keys : Vec < PublicKey > ,
472500 context : HashMap < & ' static str , serde_json:: Value > ,
501+ time_config : TimeConfig ,
473502 }
474503
475504 impl Asserter {
476505 fn new ( parameters : ValidationParameters ) -> Self {
477- Self { parameters, root_keys : ROOT_PUBLIC_KEYS . clone ( ) , context : Default :: default ( ) }
506+ Self {
507+ parameters,
508+ root_keys : ROOT_PUBLIC_KEYS . clone ( ) ,
509+ context : Default :: default ( ) ,
510+ time_config : TimeConfig :: System ,
511+ }
478512 }
479513
480514 fn with_context ( mut self , context : HashMap < & ' static str , serde_json:: Value > ) -> Self {
481515 self . context = context;
482516 self
483517 }
484518
519+ fn with_current_time ( mut self , time : DateTime < Utc > ) -> Self {
520+ self . time_config = TimeConfig :: Mock ( time) ;
521+ self
522+ }
523+
485524 fn log_tokens ( envelope : & NucTokenEnvelope ) {
486525 // Log this so we can debug tests based on their output
487526 println ! ( "Token being asserted: {}" , serde_json:: to_string_pretty( envelope. token( ) . token( ) ) . unwrap( ) ) ;
@@ -491,22 +530,28 @@ mod tests {
491530 ) ;
492531 }
493532
494- fn assert_failure < E : Into < ValidationError > > ( self , envelope : NucTokenEnvelope , expected_failure : E ) {
533+ fn validate ( self , envelope : NucTokenEnvelope ) -> Result < ValidatedNucToken , ValidationError > {
495534 Self :: log_tokens ( & envelope) ;
496535
536+ let mut validator = NucValidator :: new ( & self . root_keys ) ;
537+ validator. time_provider = match self . time_config {
538+ TimeConfig :: System => Box :: new ( SystemClockTimeProvider ) ,
539+ TimeConfig :: Mock ( time) => Box :: new ( MockTimeProvider ( time) ) ,
540+ } ;
541+ validator. validate ( envelope, self . parameters , & self . context )
542+ }
543+
544+ fn assert_failure < E : Into < ValidationError > > ( self , envelope : NucTokenEnvelope , expected_failure : E ) {
497545 let expected_failure = expected_failure. into ( ) ;
498- match NucValidator :: new ( & self . root_keys ) . validate ( envelope, self . parameters , & self . context ) {
546+ match self . validate ( envelope) {
499547 Ok ( _) => panic ! ( "validation succeeded" ) ,
500548 Err ( e) if e. to_string ( ) == expected_failure. to_string ( ) => ( ) ,
501549 Err ( e) => panic ! ( "unexpected type of failure: {e}" ) ,
502550 } ;
503551 }
504552
505553 fn assert_success ( self , envelope : NucTokenEnvelope ) -> ValidatedNucToken {
506- Self :: log_tokens ( & envelope) ;
507- NucValidator :: new ( & self . root_keys )
508- . validate ( envelope, self . parameters , & self . context )
509- . expect ( "validation failed" )
554+ self . validate ( envelope) . expect ( "validation failed" )
510555 }
511556 }
512557
@@ -757,8 +802,7 @@ mod tests {
757802 let root = base. clone ( ) . not_before ( root_not_before) . issued_by_root ( ) ;
758803 let last = base. not_before ( last_not_before) . issued_by ( key) ;
759804 let envelope = Chainer :: default ( ) . chain ( [ root, last] ) ;
760- let parameters = ValidationParameters { current_time : now, ..Default :: default ( ) } ;
761- Asserter :: new ( parameters) . assert_failure ( envelope, ValidationKind :: NotBeforeBackwards ) ;
805+ Asserter :: default ( ) . with_current_time ( now) . assert_failure ( envelope, ValidationKind :: NotBeforeBackwards ) ;
762806 }
763807
764808 #[ test]
@@ -771,8 +815,7 @@ mod tests {
771815 let root = base. clone ( ) . not_before ( not_before) . issued_by_root ( ) ;
772816 let last = base. issued_by ( key) ;
773817 let envelope = Chainer :: default ( ) . chain ( [ root, last] ) ;
774- let parameters = ValidationParameters { current_time : now, ..Default :: default ( ) } ;
775- Asserter :: new ( parameters) . assert_failure ( envelope, ValidationKind :: NotBeforeNotMet ) ;
818+ Asserter :: default ( ) . with_current_time ( now) . assert_failure ( envelope, ValidationKind :: NotBeforeNotMet ) ;
776819 }
777820
778821 #[ test]
@@ -785,8 +828,7 @@ mod tests {
785828 let root = base. clone ( ) . issued_by_root ( ) ;
786829 let last = base. not_before ( not_before) . issued_by ( key) ;
787830 let envelope = Chainer :: default ( ) . chain ( [ root, last] ) ;
788- let parameters = ValidationParameters { current_time : now, ..Default :: default ( ) } ;
789- Asserter :: new ( parameters) . assert_failure ( envelope, ValidationKind :: NotBeforeNotMet ) ;
831+ Asserter :: default ( ) . with_current_time ( now) . assert_failure ( envelope, ValidationKind :: NotBeforeNotMet ) ;
790832 }
791833
792834 #[ test]
@@ -916,8 +958,7 @@ mod tests {
916958 let root = base. clone ( ) . expires_at ( expires_at) . issued_by_root ( ) ;
917959 let last = base. issued_by ( key) ;
918960 let envelope = Chainer :: default ( ) . chain ( [ root, last] ) ;
919- let parameters = ValidationParameters { current_time : now, ..Default :: default ( ) } ;
920- Asserter :: new ( parameters) . assert_failure ( envelope, ValidationKind :: TokenExpired ) ;
961+ Asserter :: default ( ) . with_current_time ( now) . assert_failure ( envelope, ValidationKind :: TokenExpired ) ;
921962 }
922963
923964 #[ test]
@@ -930,8 +971,7 @@ mod tests {
930971 let root = base. clone ( ) . issued_by_root ( ) ;
931972 let last = base. expires_at ( expires_at) . issued_by ( key) ;
932973 let envelope = Chainer :: default ( ) . chain ( [ root, last] ) ;
933- let parameters = ValidationParameters { current_time : now, ..Default :: default ( ) } ;
934- Asserter :: new ( parameters) . assert_failure ( envelope, ValidationKind :: TokenExpired ) ;
974+ Asserter :: default ( ) . with_current_time ( now) . assert_failure ( envelope, ValidationKind :: TokenExpired ) ;
935975 }
936976
937977 #[ test]
0 commit comments