# HG changeset patch # User Alex Gaynor <alex.gaynor@gmail.com> # Date 1593978719 14400 # Sun Jul 05 15:51:59 2020 -0400 # Node ID 94d13f1aac9374df9f0d38bf74c94510082d6c5c # Parent 5aca1c6f3a7de44d1d353abb5436b320c2f83415 Enforce that X.509 versions on valid on parse. (#5299) Closes #5290 diff --git a/CHANGELOG.rst b/CHANGELOG.rst --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -20,6 +20,9 @@ :meth:`~cryptography.hazmat.primitives.asymmetric.rsa.generate_private_key` no longer accepts ``public_exponent`` values except 65537 and 3 (the latter for legacy purposes). +* **BACKWARDS INCOMPATIBLE:** X.509 certificate parsing now enforces that the + ``version`` field contains a valid value, rather than deferring this check + until :attr:`~cryptography.x509.Certificate.version` is accessed. * Deprecated support for Python 2. At the time there is no time table for actually dropping support, however we strongly encourage all users to upgrade their Python, as Python 2 no longer receives support from the Python core diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -24,9 +24,19 @@ @utils.register_interface(x509.Certificate) class _Certificate(object): - def __init__(self, backend, x509): + def __init__(self, backend, x509_cert): self._backend = backend - self._x509 = x509 + self._x509 = x509_cert + + version = self._backend._lib.X509_get_version(self._x509) + if version == 0: + self._version = x509.Version.v1 + elif version == 2: + self._version = x509.Version.v3 + else: + raise x509.InvalidVersion( + "{} is not a valid X509 version".format(version), version + ) def __repr__(self): return "<Certificate(subject={}, ...)>".format(self.subject) @@ -49,17 +59,7 @@ h.update(self.public_bytes(serialization.Encoding.DER)) return h.finalize() - @property - def version(self): - version = self._backend._lib.X509_get_version(self._x509) - if version == 0: - return x509.Version.v1 - elif version == 2: - return x509.Version.v3 - else: - raise x509.InvalidVersion( - "{} is not a valid X509 version".format(version), version - ) + version = utils.read_only_property("_version") @property def serial_number(self): diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -1000,13 +1000,12 @@ assert cert.version is x509.Version.v3 def test_invalid_version_cert(self, backend): - cert = _load_cert( - os.path.join("x509", "custom", "invalid_version.pem"), - x509.load_pem_x509_certificate, - backend - ) with pytest.raises(x509.InvalidVersion) as exc: - cert.version + _load_cert( + os.path.join("x509", "custom", "invalid_version.pem"), + x509.load_pem_x509_certificate, + backend + ) assert exc.value.parsed_version == 7