@@ -316,7 +316,75 @@ impl From<Error> for ControlFlow<Error, Error> {
316316
317317impl fmt:: Display for Error {
318318 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
319- write ! ( f, "{:?}" , self )
319+ match self {
320+ Self :: CertExpired { time, not_after } => write ! (
321+ f,
322+ "certificate expired: current time is {}, \
323+ but certificate is not valid after {} \
324+ ({} seconds ago)",
325+ time. as_secs( ) ,
326+ not_after. as_secs( ) ,
327+ time. as_secs( ) . saturating_sub( not_after. as_secs( ) )
328+ ) ,
329+
330+ Self :: CertNotValidYet { time, not_before } => write ! (
331+ f,
332+ "certificate not valid yet: current time is {}, \
333+ but certificate is not valid before {} \
334+ ({} seconds in future)",
335+ time. as_secs( ) ,
336+ not_before. as_secs( ) ,
337+ not_before. as_secs( ) . saturating_sub( time. as_secs( ) )
338+ ) ,
339+
340+ Self :: CrlExpired { time, next_update } => write ! (
341+ f,
342+ "certificate revocation list expired: \
343+ current time is {}, \
344+ but CRL is not valid after {} \
345+ ({} seconds ago)",
346+ time. as_secs( ) ,
347+ next_update. as_secs( ) ,
348+ time. as_secs( ) . saturating_sub( next_update. as_secs( ) )
349+ ) ,
350+
351+ #[ cfg( all( feature = "alloc" , feature = "std" ) ) ]
352+ Self :: CertNotValidForName ( InvalidNameContext {
353+ expected,
354+ presented,
355+ } ) => {
356+ write ! (
357+ f,
358+ "certificate not valid for name: {:?} is required, but certificate " ,
359+ expected. to_str( )
360+ ) ?;
361+
362+ match presented. as_slice ( ) {
363+ & [ ] => write ! (
364+ f,
365+ "is not valid for any names (according to its subjectAltName extension)"
366+ ) ,
367+ [ one] => write ! ( f, "is only valid for {}" , one) ,
368+ many => {
369+ write ! ( f, "is only valid for " ) ?;
370+
371+ let n = many. len ( ) ;
372+ let all_but_last = & many[ ..n - 1 ] ;
373+ let last = & many[ n - 1 ] ;
374+
375+ for ( i, name) in all_but_last. iter ( ) . enumerate ( ) {
376+ write ! ( f, "{}" , name) ?;
377+ if i < n - 2 {
378+ write ! ( f, ", " ) ?;
379+ }
380+ }
381+ write ! ( f, " or {}" , last)
382+ }
383+ }
384+ }
385+
386+ other => write ! ( f, "{:?}" , other) ,
387+ }
320388 }
321389}
322390
@@ -371,3 +439,100 @@ pub enum DerTypeId {
371439 RevokedCertEntry ,
372440 IssuingDistributionPoint ,
373441}
442+
443+ #[ cfg( test) ]
444+ mod tests {
445+ use super :: * ;
446+ use std:: string:: ToString ;
447+ use std:: time:: Duration ;
448+
449+ #[ test]
450+ fn error_display ( ) {
451+ assert_eq ! (
452+ "certificate expired: current time is 320, \
453+ but certificate is not valid after 300 (20 seconds ago)",
454+ Error :: CertExpired {
455+ time: UnixTime :: since_unix_epoch( Duration :: from_secs( 320 ) ) ,
456+ not_after: UnixTime :: since_unix_epoch( Duration :: from_secs( 300 ) ) ,
457+ }
458+ . to_string( ) ,
459+ ) ;
460+
461+ assert_eq ! (
462+ "certificate not valid yet: current time is 300, \
463+ but certificate is not valid before 320 (20 seconds in future)",
464+ Error :: CertNotValidYet {
465+ time: UnixTime :: since_unix_epoch( Duration :: from_secs( 300 ) ) ,
466+ not_before: UnixTime :: since_unix_epoch( Duration :: from_secs( 320 ) ) ,
467+ }
468+ . to_string( ) ,
469+ ) ;
470+
471+ assert_eq ! (
472+ "certificate revocation list expired: current time \
473+ is 320, but CRL is not valid after 300 (20 seconds ago)",
474+ Error :: CrlExpired {
475+ time: UnixTime :: since_unix_epoch( Duration :: from_secs( 320 ) ) ,
476+ next_update: UnixTime :: since_unix_epoch( Duration :: from_secs( 300 ) ) ,
477+ }
478+ . to_string( ) ,
479+ ) ;
480+
481+ // name errors
482+ #[ cfg( all( feature = "alloc" , feature = "std" ) ) ]
483+ {
484+ assert_eq ! (
485+ "certificate not valid for name: \" example.com\" is required, \
486+ but certificate is not valid for any names (according to its \
487+ subjectAltName extension)",
488+ Error :: CertNotValidForName ( InvalidNameContext {
489+ expected: "example.com" . try_into( ) . unwrap( ) ,
490+ presented: vec![ ] ,
491+ } )
492+ . to_string( ) ,
493+ ) ;
494+
495+ assert_eq ! (
496+ "certificate not valid for name: \" example.com\" is required, \
497+ but certificate is only valid for DnsName(\" foo.com\" )",
498+ Error :: CertNotValidForName ( InvalidNameContext {
499+ expected: "example.com" . try_into( ) . unwrap( ) ,
500+ presented: vec![ "DnsName(\" foo.com\" )" . to_string( ) , ] ,
501+ } )
502+ . to_string( ) ,
503+ ) ;
504+
505+ assert_eq ! (
506+ "certificate not valid for name: \" example.com\" is required, \
507+ but certificate is only valid for DnsName(\" foo.com\" ) \
508+ or DnsName(\" cowboy.org\" )",
509+ Error :: CertNotValidForName ( InvalidNameContext {
510+ expected: "example.com" . try_into( ) . unwrap( ) ,
511+ presented: vec![
512+ "DnsName(\" foo.com\" )" . to_string( ) ,
513+ "DnsName(\" cowboy.org\" )" . to_string( ) ,
514+ ] ,
515+ } )
516+ . to_string( ) ,
517+ ) ;
518+
519+ assert_eq ! (
520+ "certificate not valid for name: \" example.com\" is required, \
521+ but certificate is only valid for DnsName(\" foo.com\" ), \
522+ DnsName(\" cowboy.org\" ) or IpAddress(127.0.0.1)",
523+ Error :: CertNotValidForName ( InvalidNameContext {
524+ expected: "example.com" . try_into( ) . unwrap( ) ,
525+ presented: vec![
526+ "DnsName(\" foo.com\" )" . to_string( ) ,
527+ "DnsName(\" cowboy.org\" )" . to_string( ) ,
528+ "IpAddress(127.0.0.1)" . to_string( )
529+ ] ,
530+ } )
531+ . to_string( ) ,
532+ ) ;
533+ }
534+
535+ // other errors (fall back to fmt::Debug)
536+ assert_eq ! ( "BadDerTime" , Error :: BadDerTime . to_string( ) ) ;
537+ }
538+ }
0 commit comments