From 0a164d2c985b4655929591b191824ed361890b8d Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Mon, 10 May 2021 13:27:54 +0200 Subject: [PATCH 4/4] Use well-defined enum representation Python 3.10 changed enum's object and string representation. PyCA cryptography now uses a custom subclass of enum.Enum() will well-defined __repr__ and __str__ from Python 3.9. Related: https://bugs.python.org/issue40066 Fixes: https://github.com/pyca/cryptography/issues/5995 Signed-off-by: Christian Heimes --- .github/workflows/ci.yml | 13 +++++++------ src/cryptography/exceptions.py | 4 ++-- .../hazmat/primitives/_serialization.py | 11 ++++++----- src/cryptography/hazmat/primitives/kdf/kbkdf.py | 5 ++--- .../hazmat/primitives/serialization/pkcs7.py | 4 ++-- src/cryptography/utils.py | 11 +++++++++++ src/cryptography/x509/base.py | 4 ++-- src/cryptography/x509/certificate_transparency.py | 7 ++++--- src/cryptography/x509/extensions.py | 5 ++--- src/cryptography/x509/name.py | 3 +-- src/cryptography/x509/ocsp.py | 8 ++++---- tests/test_cryptography_utils.py | 11 +++++++++++ 12 files changed, 54 insertions(+), 32 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 747f84c1..ca298f96 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,15 +18,16 @@ jobs: - {VERSION: "3.9", TOXENV: "flake,rust,docs", COVERAGE: "false"} - {VERSION: "pypy3", TOXENV: "pypy3"} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.0l"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} - - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1j", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} - - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-alpha15"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k"}} + - {VERSION: "3.9", TOXENV: "py39-ssh", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1k", CONFIG_FLAGS: "no-engine no-rc2 no-srtp no-ct"}} + - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "openssl", VERSION: "3.0.0-alpha16"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "2.9.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.0.2"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.1.5"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.2.3"}} - {VERSION: "3.9", TOXENV: "py39", OPENSSL: {TYPE: "libressl", VERSION: "3.3.1"}} + - {VERSION: "3.10-dev", TOXENV: "py310"} RUST: - stable name: "${{ matrix.PYTHON.TOXENV }} ${{ matrix.PYTHON.OPENSSL.TYPE }} ${{ matrix.PYTHON.OPENSSL.VERSION }} ${{ matrix.PYTHON.OPENSSL.CONFIG_FLAGS }}" @@ -108,8 +109,8 @@ jobs: - {IMAGE: "sid", TOXENV: "py39"} - {IMAGE: "ubuntu-bionic", TOXENV: "py36"} - {IMAGE: "ubuntu-focal", TOXENV: "py38"} - - {IMAGE: "ubuntu-rolling", TOXENV: "py38"} - - {IMAGE: "ubuntu-rolling", TOXENV: "py38-randomorder"} + - {IMAGE: "ubuntu-rolling", TOXENV: "py39"} + - {IMAGE: "ubuntu-rolling", TOXENV: "py39-randomorder"} - {IMAGE: "fedora", TOXENV: "py39"} - {IMAGE: "alpine", TOXENV: "py38"} name: "${{ matrix.IMAGE.TOXENV }} on ${{ matrix.IMAGE.IMAGE }}" diff --git a/src/cryptography/exceptions.py b/src/cryptography/exceptions.py index f5860590..3bd98d82 100644 --- a/src/cryptography/exceptions.py +++ b/src/cryptography/exceptions.py @@ -3,10 +3,10 @@ # for complete details. -from enum import Enum +from cryptography import utils -class _Reasons(Enum): +class _Reasons(utils.Enum): BACKEND_MISSING_INTERFACE = 0 UNSUPPORTED_HASH = 1 UNSUPPORTED_CIPHER = 2 diff --git a/src/cryptography/hazmat/primitives/_serialization.py b/src/cryptography/hazmat/primitives/_serialization.py index 96a5ed9b..160a6b89 100644 --- a/src/cryptography/hazmat/primitives/_serialization.py +++ b/src/cryptography/hazmat/primitives/_serialization.py @@ -3,13 +3,14 @@ # for complete details. import abc -from enum import Enum + +from cryptography import utils # This exists to break an import cycle. These classes are normally accessible # from the serialization module. -class Encoding(Enum): +class Encoding(utils.Enum): PEM = "PEM" DER = "DER" OpenSSH = "OpenSSH" @@ -18,14 +19,14 @@ class Encoding(Enum): SMIME = "S/MIME" -class PrivateFormat(Enum): +class PrivateFormat(utils.Enum): PKCS8 = "PKCS8" TraditionalOpenSSL = "TraditionalOpenSSL" Raw = "Raw" OpenSSH = "OpenSSH" -class PublicFormat(Enum): +class PublicFormat(utils.Enum): SubjectPublicKeyInfo = "X.509 subjectPublicKeyInfo with PKCS#1" PKCS1 = "Raw PKCS#1" OpenSSH = "OpenSSH" @@ -34,7 +35,7 @@ class PublicFormat(Enum): UncompressedPoint = "X9.62 Uncompressed Point" -class ParameterFormat(Enum): +class ParameterFormat(utils.Enum): PKCS3 = "PKCS3" diff --git a/src/cryptography/hazmat/primitives/kdf/kbkdf.py b/src/cryptography/hazmat/primitives/kdf/kbkdf.py index ac36474f..75fe7d51 100644 --- a/src/cryptography/hazmat/primitives/kdf/kbkdf.py +++ b/src/cryptography/hazmat/primitives/kdf/kbkdf.py @@ -4,7 +4,6 @@ import typing -from enum import Enum from cryptography import utils from cryptography.exceptions import ( @@ -19,11 +18,11 @@ from cryptography.hazmat.primitives import constant_time, hashes, hmac from cryptography.hazmat.primitives.kdf import KeyDerivationFunction -class Mode(Enum): +class Mode(utils.Enum): CounterMode = "ctr" -class CounterLocation(Enum): +class CounterLocation(utils.Enum): BeforeFixed = "before_fixed" AfterFixed = "after_fixed" diff --git a/src/cryptography/hazmat/primitives/serialization/pkcs7.py b/src/cryptography/hazmat/primitives/serialization/pkcs7.py index bcd9e330..57aac7e3 100644 --- a/src/cryptography/hazmat/primitives/serialization/pkcs7.py +++ b/src/cryptography/hazmat/primitives/serialization/pkcs7.py @@ -3,8 +3,8 @@ # for complete details. import typing -from enum import Enum +from cryptography import utils from cryptography import x509 from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.primitives import hashes, serialization @@ -35,7 +35,7 @@ _ALLOWED_PRIVATE_KEY_TYPES = typing.Union[ ] -class PKCS7Options(Enum): +class PKCS7Options(utils.Enum): Text = "Add text/plain MIME type" Binary = "Don't translate input data into canonical MIME format" DetachedSignature = "Don't embed data in the PKCS7 structure" diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index ef0fc443..9e571cfd 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -4,6 +4,7 @@ import abc +import enum import inspect import sys import typing @@ -162,3 +163,13 @@ int_from_bytes = deprecated( "int_from_bytes is deprecated, use int.from_bytes instead", DeprecatedIn34, ) + + +# Python 3.10 changed representation of enums. We use well-defined object +# representation and string representation from Python 3.9. +class Enum(enum.Enum): + def __repr__(self): + return f"<{self.__class__.__name__}.{self._name_}: {self._value_!r}>" + + def __str__(self): + return f"{self.__class__.__name__}.{self._name_}" diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py index 5505fa3b..26ec43d5 100644 --- a/src/cryptography/x509/base.py +++ b/src/cryptography/x509/base.py @@ -7,8 +7,8 @@ import abc import datetime import os import typing -from enum import Enum +from cryptography import utils from cryptography.hazmat._types import _PRIVATE_KEY_TYPES, _PUBLIC_KEY_TYPES from cryptography.hazmat.backends import _get_backend from cryptography.hazmat.primitives import hashes, serialization @@ -66,7 +66,7 @@ def _convert_to_naive_utc_time(time: datetime.datetime) -> datetime.datetime: return time -class Version(Enum): +class Version(utils.Enum): v1 = 0 v3 = 2 diff --git a/src/cryptography/x509/certificate_transparency.py b/src/cryptography/x509/certificate_transparency.py index d51bee92..d80f051a 100644 --- a/src/cryptography/x509/certificate_transparency.py +++ b/src/cryptography/x509/certificate_transparency.py @@ -5,15 +5,16 @@ import abc import datetime -from enum import Enum +from cryptography import utils -class LogEntryType(Enum): + +class LogEntryType(utils.Enum): X509_CERTIFICATE = 0 PRE_CERTIFICATE = 1 -class Version(Enum): +class Version(utils.Enum): v1 = 0 diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py index 6cae016a..742f1fa2 100644 --- a/src/cryptography/x509/extensions.py +++ b/src/cryptography/x509/extensions.py @@ -8,7 +8,6 @@ import datetime import hashlib import ipaddress import typing -from enum import Enum from cryptography import utils from cryptography.hazmat._der import ( @@ -634,7 +633,7 @@ class DistributionPoint(object): crl_issuer = utils.read_only_property("_crl_issuer") -class ReasonFlags(Enum): +class ReasonFlags(utils.Enum): unspecified = "unspecified" key_compromise = "keyCompromise" ca_compromise = "cACompromise" @@ -978,7 +977,7 @@ class TLSFeature(ExtensionType): return hash(tuple(self._features)) -class TLSFeatureType(Enum): +class TLSFeatureType(utils.Enum): # status_request is defined in RFC 6066 and is used for what is commonly # called OCSP Must-Staple when present in the TLS Feature extension in an # X.509 certificate. diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py index a579aa21..9069a9f4 100644 --- a/src/cryptography/x509/name.py +++ b/src/cryptography/x509/name.py @@ -3,14 +3,13 @@ # for complete details. import typing -from enum import Enum from cryptography import utils from cryptography.hazmat.backends import _get_backend from cryptography.x509.oid import NameOID, ObjectIdentifier -class _ASN1Type(Enum): +class _ASN1Type(utils.Enum): UTF8String = 12 NumericString = 18 PrintableString = 19 diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py index 1c5de73e..bcf210c1 100644 --- a/src/cryptography/x509/ocsp.py +++ b/src/cryptography/x509/ocsp.py @@ -6,8 +6,8 @@ import abc import datetime import typing -from enum import Enum +from cryptography import utils from cryptography import x509 from cryptography.hazmat.primitives import hashes, serialization from cryptography.x509.base import ( @@ -27,12 +27,12 @@ _OIDS_TO_HASH = { } -class OCSPResponderEncoding(Enum): +class OCSPResponderEncoding(utils.Enum): HASH = "By Hash" NAME = "By Name" -class OCSPResponseStatus(Enum): +class OCSPResponseStatus(utils.Enum): SUCCESSFUL = 0 MALFORMED_REQUEST = 1 INTERNAL_ERROR = 2 @@ -58,7 +58,7 @@ def _verify_algorithm(algorithm): ) -class OCSPCertStatus(Enum): +class OCSPCertStatus(utils.Enum): GOOD = 0 REVOKED = 1 UNKNOWN = 2 diff --git a/tests/test_cryptography_utils.py b/tests/test_cryptography_utils.py index 6b795e0c..803997ac 100644 --- a/tests/test_cryptography_utils.py +++ b/tests/test_cryptography_utils.py @@ -2,6 +2,7 @@ # 2.0, and the BSD License. See the LICENSE file in the root of this repository # for complete details. +import enum import typing import pytest @@ -51,3 +52,13 @@ class TestCachedProperty(object): assert len(accesses) == 1 assert t.t == 14 assert len(accesses) == 1 + + +def test_enum(): + class TestEnum(utils.Enum): + value = "something" + + assert issubclass(TestEnum, enum.Enum) + assert isinstance(TestEnum.value, enum.Enum) + assert repr(TestEnum.value) == "" + assert str(TestEnum.value) == "TestEnum.value" -- 2.31.1