From 2e9c7df922edbc59981a2c0fdb6ea4f15fdd8afc Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 22 Jan 2019 06:59:06 -0600 Subject: allow asn1 times of 1950-01-01 and later. (#4728) * allow asn1 times of 1950-01-01 and later. * add a test * pretty up the test --- src/cryptography/x509/base.py | 32 ++++++++++++++--------------- src/cryptography/x509/ocsp.py | 8 ++++---- tests/x509/test_x509.py | 33 ++++++++++++++++++++++++++++-- tests/x509/test_x509_crlbuilder.py | 8 ++++---- tests/x509/test_x509_revokedcertbuilder.py | 4 ++-- 5 files changed, 57 insertions(+), 28 deletions(-) diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index a3b334a1..63c2e3c6 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -17,7 +17,7 @@ from cryptography.x509.extensions import Extension, ExtensionType from cryptography.x509.name import Name -_UNIX_EPOCH = datetime.datetime(1970, 1, 1) +_EARLIEST_UTC_TIME = datetime.datetime(1950, 1, 1) def _reject_duplicate_extension(extension, extensions): @@ -516,9 +516,9 @@ class CertificateBuilder(object): if self._not_valid_before is not None: raise ValueError('The not valid before may only be set once.') time = _convert_to_naive_utc_time(time) - if time <= _UNIX_EPOCH: - raise ValueError('The not valid before date must be after the unix' - ' epoch (1970 January 1).') + if time < _EARLIEST_UTC_TIME: + raise ValueError('The not valid before date must be on or after' + ' 1950 January 1).') if self._not_valid_after is not None and time > self._not_valid_after: raise ValueError( 'The not valid before date must be before the not valid after ' @@ -539,9 +539,9 @@ class CertificateBuilder(object): if self._not_valid_after is not None: raise ValueError('The not valid after may only be set once.') time = _convert_to_naive_utc_time(time) - if time <= _UNIX_EPOCH: - raise ValueError('The not valid after date must be after the unix' - ' epoch (1970 January 1).') + if time < _EARLIEST_UTC_TIME: + raise ValueError('The not valid after date must be on or after' + ' 1950 January 1.') if (self._not_valid_before is not None and time < self._not_valid_before): raise ValueError( @@ -620,9 +620,9 @@ class CertificateRevocationListBuilder(object): if self._last_update is not None: raise ValueError('Last update may only be set once.') last_update = _convert_to_naive_utc_time(last_update) - if last_update <= _UNIX_EPOCH: - raise ValueError('The last update date must be after the unix' - ' epoch (1970 January 1).') + if last_update < _EARLIEST_UTC_TIME: + raise ValueError('The last update date must be on or after' + ' 1950 January 1.') if self._next_update is not None and last_update > self._next_update: raise ValueError( 'The last update date must be before the next update date.' @@ -638,9 +638,9 @@ class CertificateRevocationListBuilder(object): if self._next_update is not None: raise ValueError('Last update may only be set once.') next_update = _convert_to_naive_utc_time(next_update) - if next_update <= _UNIX_EPOCH: - raise ValueError('The last update date must be after the unix' - ' epoch (1970 January 1).') + if next_update < _EARLIEST_UTC_TIME: + raise ValueError('The last update date must be on or after' + ' 1950 January 1.') if self._last_update is not None and next_update < self._last_update: raise ValueError( 'The next update date must be after the last update date.' @@ -720,9 +720,9 @@ class RevokedCertificateBuilder(object): if self._revocation_date is not None: raise ValueError('The revocation date may only be set once.') time = _convert_to_naive_utc_time(time) - if time <= _UNIX_EPOCH: - raise ValueError('The revocation date must be after the unix' - ' epoch (1970 January 1).') + if time < _EARLIEST_UTC_TIME: + raise ValueError('The revocation date must be on or after' + ' 1950 January 1.') return RevokedCertificateBuilder( self._serial_number, time, self._extensions ) diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py index 97933b1f..aae9b626 100644 --- a/src/cryptography/x509/ocsp.py +++ b/src/cryptography/x509/ocsp.py @@ -13,7 +13,7 @@ import six from cryptography import x509 from cryptography.hazmat.primitives import hashes from cryptography.x509.base import ( - _UNIX_EPOCH, _convert_to_naive_utc_time, _reject_duplicate_extension + _EARLIEST_UTC_TIME, _convert_to_naive_utc_time, _reject_duplicate_extension ) @@ -154,9 +154,9 @@ class _SingleResponse(object): raise TypeError("revocation_time must be a datetime object") revocation_time = _convert_to_naive_utc_time(revocation_time) - if revocation_time <= _UNIX_EPOCH: - raise ValueError('The revocation_time must be after the unix' - ' epoch (1970 January 1).') + if revocation_time < _EARLIEST_UTC_TIME: + raise ValueError('The revocation_time must be on or after' + ' 1950 January 1.') if ( revocation_reason is not None and diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 55f5ddda..c8c863fb 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -2027,6 +2027,35 @@ class TestCertificateBuilder(object): cert = cert_builder.sign(private_key, hashes.SHA256(), backend) assert cert.not_valid_after == utc_time + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + def test_earliest_time(self, backend): + time = datetime.datetime(1950, 1, 1) + private_key = RSA_KEY_2048.private_key(backend) + cert_builder = x509.CertificateBuilder().subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + ).issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + ).serial_number( + 1 + ).public_key( + private_key.public_key() + ).not_valid_before( + time + ).not_valid_after( + time + ) + cert = cert_builder.sign(private_key, hashes.SHA256(), backend) + assert cert.not_valid_before == time + assert cert.not_valid_after == time + parsed = Certificate.load( + cert.public_bytes(serialization.Encoding.DER) + ) + not_before = parsed['tbs_certificate']['validity']['not_before'] + not_after = parsed['tbs_certificate']['validity']['not_after'] + assert not_before.chosen.tag == 23 # UTCTime + assert not_after.chosen.tag == 23 # UTCTime + def test_invalid_not_valid_after(self): with pytest.raises(TypeError): x509.CertificateBuilder().not_valid_after(104204304504) @@ -2036,7 +2065,7 @@ class TestCertificateBuilder(object): with pytest.raises(ValueError): x509.CertificateBuilder().not_valid_after( - datetime.datetime(1960, 8, 10) + datetime.datetime(1940, 8, 10) ) def test_not_valid_after_may_only_be_set_once(self): @@ -2082,7 +2111,7 @@ class TestCertificateBuilder(object): with pytest.raises(ValueError): x509.CertificateBuilder().not_valid_before( - datetime.datetime(1960, 8, 10) + datetime.datetime(1940, 8, 10) ) def test_not_valid_before_may_only_be_set_once(self): diff --git a/tests/x509/test_x509_crlbuilder.py b/tests/x509/test_x509_crlbuilder.py index e90fd3fd..5f220bca 100644 --- a/tests/x509/test_x509_crlbuilder.py +++ b/tests/x509/test_x509_crlbuilder.py @@ -62,10 +62,10 @@ class TestCertificateRevocationListBuilder(object): with pytest.raises(TypeError): builder.last_update("notadatetime") - def test_last_update_before_unix_epoch(self): + def test_last_update_before_1950(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(ValueError): - builder.last_update(datetime.datetime(1960, 8, 10)) + builder.last_update(datetime.datetime(1940, 8, 10)) def test_set_last_update_twice(self): builder = x509.CertificateRevocationListBuilder().last_update( @@ -97,10 +97,10 @@ class TestCertificateRevocationListBuilder(object): with pytest.raises(TypeError): builder.next_update("notadatetime") - def test_next_update_before_unix_epoch(self): + def test_next_update_before_1950(self): builder = x509.CertificateRevocationListBuilder() with pytest.raises(ValueError): - builder.next_update(datetime.datetime(1960, 8, 10)) + builder.next_update(datetime.datetime(1940, 8, 10)) def test_set_next_update_twice(self): builder = x509.CertificateRevocationListBuilder().next_update( diff --git a/tests/x509/test_x509_revokedcertbuilder.py b/tests/x509/test_x509_revokedcertbuilder.py index e3a06509..75c6b269 100644 --- a/tests/x509/test_x509_revokedcertbuilder.py +++ b/tests/x509/test_x509_revokedcertbuilder.py @@ -80,10 +80,10 @@ class TestRevokedCertificateBuilder(object): with pytest.raises(TypeError): x509.RevokedCertificateBuilder().revocation_date("notadatetime") - def test_revocation_date_before_unix_epoch(self): + def test_revocation_date_before_1950(self): with pytest.raises(ValueError): x509.RevokedCertificateBuilder().revocation_date( - datetime.datetime(1960, 8, 10) + datetime.datetime(1940, 8, 10) ) def test_set_revocation_date_twice(self): -- cgit v1.2.3