@@ -86,6 +86,12 @@ def have_verify_flags():
8686 # 0.9.8 or higher
8787 return ssl .OPENSSL_VERSION_INFO >= (0 , 9 , 8 , 0 , 15 )
8888
89+ def utc_offset (): #NOTE: ignore issues like #1647654
90+ # local time = utc time + utc offset
91+ if time .daylight and time .localtime ().tm_isdst > 0 :
92+ return - time .altzone # seconds
93+ return - time .timezone
94+
8995def asn1time (cert_time ):
9096 # Some versions of OpenSSL ignore seconds, see #18207
9197 # 0.9.8.i
@@ -651,6 +657,71 @@ def test_unsupported_dtls(self):
651657 ctx .wrap_socket (s )
652658 self .assertEqual (str (cx .exception ), "only stream sockets are supported" )
653659
660+ def cert_time_ok (self , timestring , timestamp ):
661+ self .assertEqual (ssl .cert_time_to_seconds (timestring ), timestamp )
662+
663+ def cert_time_fail (self , timestring ):
664+ with self .assertRaises (ValueError ):
665+ ssl .cert_time_to_seconds (timestring )
666+
667+ @unittest .skipUnless (utc_offset (),
668+ 'local time needs to be different from UTC' )
669+ def test_cert_time_to_seconds_timezone (self ):
670+ # Issue #19940: ssl.cert_time_to_seconds() returns wrong
671+ # results if local timezone is not UTC
672+ self .cert_time_ok ("May 9 00:00:00 2007 GMT" , 1178668800.0 )
673+ self .cert_time_ok ("Jan 5 09:34:43 2018 GMT" , 1515144883.0 )
674+
675+ def test_cert_time_to_seconds (self ):
676+ timestring = "Jan 5 09:34:43 2018 GMT"
677+ ts = 1515144883.0
678+ self .cert_time_ok (timestring , ts )
679+ # accept keyword parameter, assert its name
680+ self .assertEqual (ssl .cert_time_to_seconds (cert_time = timestring ), ts )
681+ # accept both %e and %d (space or zero generated by strftime)
682+ self .cert_time_ok ("Jan 05 09:34:43 2018 GMT" , ts )
683+ # case-insensitive
684+ self .cert_time_ok ("JaN 5 09:34:43 2018 GmT" , ts )
685+ self .cert_time_fail ("Jan 5 09:34 2018 GMT" ) # no seconds
686+ self .cert_time_fail ("Jan 5 09:34:43 2018" ) # no GMT
687+ self .cert_time_fail ("Jan 5 09:34:43 2018 UTC" ) # not GMT timezone
688+ self .cert_time_fail ("Jan 35 09:34:43 2018 GMT" ) # invalid day
689+ self .cert_time_fail ("Jon 5 09:34:43 2018 GMT" ) # invalid month
690+ self .cert_time_fail ("Jan 5 24:00:00 2018 GMT" ) # invalid hour
691+ self .cert_time_fail ("Jan 5 09:60:43 2018 GMT" ) # invalid minute
692+
693+ newyear_ts = 1230768000.0
694+ # leap seconds
695+ self .cert_time_ok ("Dec 31 23:59:60 2008 GMT" , newyear_ts )
696+ # same timestamp
697+ self .cert_time_ok ("Jan 1 00:00:00 2009 GMT" , newyear_ts )
698+
699+ self .cert_time_ok ("Jan 5 09:34:59 2018 GMT" , 1515144899 )
700+ # allow 60th second (even if it is not a leap second)
701+ self .cert_time_ok ("Jan 5 09:34:60 2018 GMT" , 1515144900 )
702+ # allow 2nd leap second for compatibility with time.strptime()
703+ self .cert_time_ok ("Jan 5 09:34:61 2018 GMT" , 1515144901 )
704+ self .cert_time_fail ("Jan 5 09:34:62 2018 GMT" ) # invalid seconds
705+
706+ # no special treatement for the special value:
707+ # 99991231235959Z (rfc 5280)
708+ self .cert_time_ok ("Dec 31 23:59:59 9999 GMT" , 253402300799.0 )
709+
710+ @support .run_with_locale ('LC_ALL' , '' )
711+ def test_cert_time_to_seconds_locale (self ):
712+ # `cert_time_to_seconds()` should be locale independent
713+
714+ def local_february_name ():
715+ return time .strftime ('%b' , (1 , 2 , 3 , 4 , 5 , 6 , 0 , 0 , 0 ))
716+
717+ if local_february_name ().lower () == 'feb' :
718+ self .skipTest ("locale-specific month name needs to be "
719+ "different from C locale" )
720+
721+ # locale-independent
722+ self .cert_time_ok ("Feb 9 00:00:00 2007 GMT" , 1170979200.0 )
723+ self .cert_time_fail (local_february_name () + " 9 00:00:00 2007 GMT" )
724+
654725
655726class ContextTests (unittest .TestCase ):
656727
0 commit comments