From 5a48552b4b7fc4d108b6d45232769f111fe38896 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 6 May 2015 00:29:12 -0500 Subject: add CRLDistributionPoints and associated classes --- docs/x509.rst | 72 ++++++++++++ src/cryptography/x509.py | 144 ++++++++++++++++++++++++ tests/test_x509_ext.py | 282 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 498 insertions(+) diff --git a/docs/x509.rst b/docs/x509.rst index f4ea2a52..9ef8e149 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -781,6 +781,8 @@ X.509 Extensions .. class:: AccessDescription + .. versionadded:: 0.9 + .. attribute:: access_method :type: :class:`ObjectIdentifier` @@ -798,6 +800,76 @@ X.509 Extensions Where to access the information defined by the access method. +.. class:: CRLDistributionPoints + + .. versionadded:: 0.9 + + The CRL distribution points extension identifies how CRL information is + obtained. It is an iterable, containing one or more + :class:`DistributionPoint` instances. + +.. class:: DistributionPoint + + .. versionadded:: 0.9 + + .. attribute:: distribution_point + + :type: list of :class:`GeneralName` instances, :class:`Name`, or None + + This field describes methods to retrieve the CRL. + + .. attribute:: crl_issuer + + :type: list of :class:`GeneralName` instances or None + + Information about the issuer of the CRL. + + .. attribute:: reasons + + :type: :class:`ReasonFlags` or None + + The reasons a given distribution point may be used for when performing + revocation checks. + +.. class:: ReasonFlags + + .. versionadded:: 0.9 + + This class holds reasons a distribution point may be used for when + performing revocation checks. + + .. attribute:: key_compromise + + :type: bool + + .. attribute:: ca_compromise + + :type: bool + + .. attribute:: affiliation_changed + + :type: bool + + .. attribute:: superseded + + :type: bool + + .. attribute:: cessation_of_operation + + :type: bool + + .. attribute:: certificate_hold + + :type: bool + + .. attribute:: privilege_withdrawn + + :type: bool + + .. attribute:: aa_compromise + + :type: bool + Object Identifiers ~~~~~~~~~~~~~~~~~~ diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 0d87cd51..671294e2 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -481,6 +481,150 @@ class SubjectKeyIdentifier(object): return not self == other +class CRLDistributionPoints(object): + def __init__(self, distribution_points): + if not all( + isinstance(x, DistributionPoint) for x in distribution_points + ): + raise TypeError( + "distribution_points must be a list of DistributionPoint " + "objects" + ) + + self._distribution_points = distribution_points + + def __iter__(self): + return iter(self._distribution_points) + + def __len__(self): + return len(self._distribution_points) + + def __repr__(self): + return "".format(self._distribution_points) + + def __eq__(self, other): + if not isinstance(other, CRLDistributionPoints): + return NotImplemented + + return self._distribution_points == other._distribution_points + + def __ne__(self, other): + return not self == other + + +class DistributionPoint(object): + def __init__(self, distribution_point, reasons, crl_issuer): + if distribution_point: + if ( + ( + isinstance(distribution_point, list) and + not all( + isinstance(x, GeneralName) for x in distribution_point + ) + ) or not isinstance(distribution_point, (list, Name)) + ): + raise TypeError( + "distribution_point must be None, a list of general names" + ", or a Name" + ) + + if crl_issuer and not all( + isinstance(x, GeneralName) for x in crl_issuer + ): + raise TypeError( + "crl_issuer must be None or a list of general names" + ) + + if reasons and not isinstance(reasons, ReasonFlags): + raise TypeError("reasons must be None or ReasonFlags") + + if reasons and not crl_issuer and not distribution_point: + raise ValueError( + "You must supply crl_issuer or distribution_point when " + "reasons is not None" + ) + + self._distribution_point = distribution_point + self._reasons = reasons + self._crl_issuer = crl_issuer + + def __repr__(self): + return ( + "".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, DistributionPoint): + return NotImplemented + + return ( + self.distribution_point == other.distribution_point and + self.reasons == other.reasons and + self.crl_issuer == other.crl_issuer + ) + + def __ne__(self, other): + return not self == other + + distribution_point = utils.read_only_property("_distribution_point") + reasons = utils.read_only_property("_reasons") + crl_issuer = utils.read_only_property("_crl_issuer") + + +class ReasonFlags(object): + def __init__(self, key_compromise, ca_compromise, affiliation_changed, + superseded, cessation_of_operation, certificate_hold, + privilege_withdrawn, aa_compromise): + self._key_compromise = key_compromise + self._ca_compromise = ca_compromise + self._affiliation_changed = affiliation_changed + self._superseded = superseded + self._cessation_of_operation = cessation_of_operation + self._certificate_hold = certificate_hold + self._privilege_withdrawn = privilege_withdrawn + self._aa_compromise = aa_compromise + + def __repr__(self): + return ( + "".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, ReasonFlags): + return NotImplemented + + return ( + self.key_compromise == other.key_compromise and + self.ca_compromise == other.ca_compromise and + self.affiliation_changed == other.affiliation_changed and + self.superseded == other.superseded and + self.cessation_of_operation == other.cessation_of_operation and + self.certificate_hold == other.certificate_hold and + self.privilege_withdrawn == other.privilege_withdrawn and + self.aa_compromise == other.aa_compromise + ) + + def __ne__(self, other): + return not self == other + + key_compromise = utils.read_only_property("_key_compromise") + ca_compromise = utils.read_only_property("_ca_compromise") + affiliation_changed = utils.read_only_property("_affiliation_changed") + superseded = utils.read_only_property("_superseded") + cessation_of_operation = utils.read_only_property( + "_cessation_of_operation" + ) + certificate_hold = utils.read_only_property("_certificate_hold") + privilege_withdrawn = utils.read_only_property("_privilege_withdrawn") + aa_compromise = utils.read_only_property("_aa_compromise") + + @six.add_metaclass(abc.ABCMeta) class GeneralName(object): @abc.abstractproperty diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 8a227953..1ccb361b 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -1318,3 +1318,285 @@ class TestAuthorityKeyIdentifierExtension(object): ) ] assert ext.value.authority_cert_serial_number == 3 + + +class TestReasonFlags(object): + def test_flags(self): + flags = x509.ReasonFlags( + True, True, False, False, True, True, False, False + ) + assert flags.key_compromise is True + assert flags.ca_compromise is True + assert flags.affiliation_changed is False + assert flags.superseded is False + assert flags.cessation_of_operation is True + assert flags.certificate_hold is True + assert flags.privilege_withdrawn is False + assert flags.aa_compromise is False + + def test_eq(self): + flags = x509.ReasonFlags( + True, True, False, False, True, True, False, False + ) + flags2 = x509.ReasonFlags( + True, True, False, False, True, True, False, False + ) + assert flags == flags2 + + def test_ne(self): + flags = x509.ReasonFlags( + True, True, False, False, True, True, False, False + ) + flags2 = x509.ReasonFlags( + True, True, False, False, True, True, False, True + ) + assert flags != flags2 + assert flags != object() + + def test_repr(self): + flags = x509.ReasonFlags( + True, True, False, False, True, True, False, False + ) + assert repr(flags) == ( + "" + ) + + +class TestDistributionPoint(object): + def test_distribution_point_list_not_general_names(self): + with pytest.raises(TypeError): + x509.DistributionPoint(["notgn"], None, None) + + def test_distribution_point_not_name(self): + with pytest.raises(TypeError): + x509.DistributionPoint("notname", None, None) + + def test_crl_issuer_not_general_names(self): + with pytest.raises(TypeError): + x509.DistributionPoint(None, None, ["notgn"]) + + def test_reason_not_reasonflags(self): + with pytest.raises(TypeError): + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + "notreasonflags", + None + ) + + def test_reason_only(self): + with pytest.raises(ValueError): + x509.DistributionPoint( + None, + x509.ReasonFlags( + True, True, False, False, True, True, False, False + ), + None + ) + + def test_eq(self): + dp = x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + x509.ReasonFlags( + False, False, False, False, False, True, False, False + ), + [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + x509.OID_COMMON_NAME, "Important CA" + ) + ]) + ) + ], + ) + dp2 = x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + x509.ReasonFlags( + False, False, False, False, False, True, False, False + ), + [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + x509.OID_COMMON_NAME, "Important CA" + ) + ]) + ) + ], + ) + assert dp == dp2 + + def test_ne(self): + dp = x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + x509.ReasonFlags( + False, False, False, False, False, True, False, False + ), + [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + x509.OID_COMMON_NAME, "Important CA" + ) + ]) + ) + ], + ) + dp2 = x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + None + ) + assert dp != dp2 + assert dp != object() + + def test_repr(self): + dp = x509.DistributionPoint( + x509.Name([ + x509.NameAttribute(x509.OID_COMMON_NAME, "myCN") + ]), + x509.ReasonFlags( + False, False, False, False, False, True, False, False + ), + [ + x509.DirectoryName( + x509.Name([ + x509.NameAttribute( + x509.OID_COMMON_NAME, "Important CA" + ) + ]) + ) + ], + ) + assert repr(dp) == ( + ", value='myCN')>" + "])>, reasons=, crl_issuer=[, value='Important CA')>])>)>])>" + ) + + +class TestCRLDistributionPoints(object): + def test_invalid_distribution_points(self): + with pytest.raises(TypeError): + x509.CRLDistributionPoints(["notadistributionpoint"]) + + def test_iter_len(self): + cdp = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://domain")], + None, + None + ), + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + x509.ReasonFlags( + True, True, True, True, True, True, True, True + ), + None + ), + ]) + assert len(cdp) == 2 + assert list(cdp) == [ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://domain")], + None, + None + ), + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + x509.ReasonFlags( + True, True, True, True, True, True, True, True + ), + None + ), + ] + + def test_repr(self): + cdp = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + x509.ReasonFlags( + True, True, True, True, True, True, True, True + ), + None + ), + ]) + assert repr(cdp) == ( + "], reasons=, crl" + "_issuer=None)>])>" + ) + + def test_eq(self): + cdp = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + x509.ReasonFlags( + True, True, True, True, True, True, True, True + ), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + cdp2 = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + x509.ReasonFlags( + True, True, True, True, True, True, True, True + ), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + assert cdp == cdp2 + + def test_ne(self): + cdp = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + x509.ReasonFlags( + True, True, True, True, True, True, True, True + ), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + cdp2 = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain2")], + x509.ReasonFlags( + True, True, True, True, True, True, True, True + ), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + cdp3 = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + x509.ReasonFlags( + True, True, True, True, True, True, True, False + ), + [x509.UniformResourceIdentifier(u"uri://thing")], + ), + ]) + cdp4 = x509.CRLDistributionPoints([ + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"ftp://domain")], + x509.ReasonFlags( + True, True, True, True, True, True, True, True + ), + [x509.UniformResourceIdentifier(u"uri://thing2")], + ), + ]) + assert cdp != cdp2 + assert cdp != cdp3 + assert cdp != cdp4 + assert cdp != object() -- cgit v1.2.3 From 4e8dacd02ec4c4b8238e5ebdfcd5ab26348ec658 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 9 May 2015 10:38:23 -0500 Subject: separate full_name/relative_name and change reasons to an enumeration --- docs/x509.rst | 49 +++++++---- src/cryptography/x509.py | 124 ++++++++++++---------------- tests/test_x509_ext.py | 207 +++++++++++++++++++++++------------------------ 3 files changed, 185 insertions(+), 195 deletions(-) diff --git a/docs/x509.rst b/docs/x509.rst index 9ef8e149..3cf4f905 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -812,11 +812,19 @@ X.509 Extensions .. versionadded:: 0.9 - .. attribute:: distribution_point + .. attribute:: full_name - :type: list of :class:`GeneralName` instances, :class:`Name`, or None + :type: list of :class:`GeneralName` instances or None + + This field describes methods to retrieve the CRL. If this is not None + then ``relative_name`` must be None. + + .. attribute:: relative_name + + :type: :class:`Name` or None - This field describes methods to retrieve the CRL. + This field describes methods to retrieve the CRL relative to the CRL + issuer. If this is not None then ``full_name`` must be None. .. attribute:: crl_issuer @@ -826,7 +834,7 @@ X.509 Extensions .. attribute:: reasons - :type: :class:`ReasonFlags` or None + :type: list of :class:`ReasonFlags` or None The reasons a given distribution point may be used for when performing revocation checks. @@ -835,40 +843,53 @@ X.509 Extensions .. versionadded:: 0.9 - This class holds reasons a distribution point may be used for when - performing revocation checks. + An enumeration for CRL reasons. + + .. attribute:: unspecified + + It is unspecified why the certificate was revoked. This reason cannot + be used as a reason flag in a :class:`DistributionPoint`. .. attribute:: key_compromise - :type: bool + This reason indicates that the private key was compromised. .. attribute:: ca_compromise - :type: bool + This reason indicates that the CA issuing the certificate was + compromised. .. attribute:: affiliation_changed - :type: bool + This reason indicates that the subject's name or other information has + changed. .. attribute:: superseded - :type: bool + This reason indicates that a certificate has been superseded. .. attribute:: cessation_of_operation - :type: bool + This reason indicates that the certificate is no longer required. .. attribute:: certificate_hold - :type: bool + This reason indicates that the certificate is on hold. .. attribute:: privilege_withdrawn - :type: bool + This reason indicates that the privilege granted by this certificate + have been withdrawn. .. attribute:: aa_compromise - :type: bool + When an attribute authority has been compromised. + + .. attribute:: remove_from_crl + + This reason indicates that the certificate was on hold and should be + removed from the CRL. This reason cannot be used as a reason flag + in a :class:`DistributionPoint`. Object Identifiers ~~~~~~~~~~~~~~~~~~ diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 671294e2..cee0cc39 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -513,20 +513,21 @@ class CRLDistributionPoints(object): class DistributionPoint(object): - def __init__(self, distribution_point, reasons, crl_issuer): - if distribution_point: - if ( - ( - isinstance(distribution_point, list) and - not all( - isinstance(x, GeneralName) for x in distribution_point - ) - ) or not isinstance(distribution_point, (list, Name)) - ): - raise TypeError( - "distribution_point must be None, a list of general names" - ", or a Name" - ) + def __init__(self, full_name, relative_name, reasons, crl_issuer): + if full_name and relative_name: + raise ValueError( + "At least one of full_name and relative_name must be None" + ) + + if full_name and not all( + isinstance(x, GeneralName) for x in full_name + ): + raise TypeError( + "full_name must be a list of GeneralName objects" + ) + + if relative_name and not isinstance(relative_name, Name): + raise TypeError("relative_name must be a Name") if crl_issuer and not all( isinstance(x, GeneralName) for x in crl_issuer @@ -535,23 +536,36 @@ class DistributionPoint(object): "crl_issuer must be None or a list of general names" ) - if reasons and not isinstance(reasons, ReasonFlags): - raise TypeError("reasons must be None or ReasonFlags") + if reasons and not all( + isinstance(x, ReasonFlags) for x in reasons + ): + raise TypeError("reasons must be None or list of ReasonFlags") + + if reasons and ( + ReasonFlags.unspecified in reasons or + ReasonFlags.remove_from_crl in reasons + ): + raise ValueError( + "unspecified and remove_from_crl are not valid reasons in a " + "DistributionPoint" + ) - if reasons and not crl_issuer and not distribution_point: + if reasons and not crl_issuer and not (full_name or relative_name): raise ValueError( - "You must supply crl_issuer or distribution_point when " + "You must supply crl_issuer, full_name, or relative_name when " "reasons is not None" ) - self._distribution_point = distribution_point + self._full_name = full_name + self._relative_name = relative_name self._reasons = reasons self._crl_issuer = crl_issuer def __repr__(self): return ( - "".format(self) + "".format(self) ) def __eq__(self, other): @@ -559,7 +573,8 @@ class DistributionPoint(object): return NotImplemented return ( - self.distribution_point == other.distribution_point and + self.full_name == other.full_name and + self.relative_name == other.relative_name and self.reasons == other.reasons and self.crl_issuer == other.crl_issuer ) @@ -567,62 +582,23 @@ class DistributionPoint(object): def __ne__(self, other): return not self == other - distribution_point = utils.read_only_property("_distribution_point") + full_name = utils.read_only_property("_full_name") + relative_name = utils.read_only_property("_relative_name") reasons = utils.read_only_property("_reasons") crl_issuer = utils.read_only_property("_crl_issuer") -class ReasonFlags(object): - def __init__(self, key_compromise, ca_compromise, affiliation_changed, - superseded, cessation_of_operation, certificate_hold, - privilege_withdrawn, aa_compromise): - self._key_compromise = key_compromise - self._ca_compromise = ca_compromise - self._affiliation_changed = affiliation_changed - self._superseded = superseded - self._cessation_of_operation = cessation_of_operation - self._certificate_hold = certificate_hold - self._privilege_withdrawn = privilege_withdrawn - self._aa_compromise = aa_compromise - - def __repr__(self): - return ( - "".format(self) - ) - - def __eq__(self, other): - if not isinstance(other, ReasonFlags): - return NotImplemented - - return ( - self.key_compromise == other.key_compromise and - self.ca_compromise == other.ca_compromise and - self.affiliation_changed == other.affiliation_changed and - self.superseded == other.superseded and - self.cessation_of_operation == other.cessation_of_operation and - self.certificate_hold == other.certificate_hold and - self.privilege_withdrawn == other.privilege_withdrawn and - self.aa_compromise == other.aa_compromise - ) - - def __ne__(self, other): - return not self == other - - key_compromise = utils.read_only_property("_key_compromise") - ca_compromise = utils.read_only_property("_ca_compromise") - affiliation_changed = utils.read_only_property("_affiliation_changed") - superseded = utils.read_only_property("_superseded") - cessation_of_operation = utils.read_only_property( - "_cessation_of_operation" - ) - certificate_hold = utils.read_only_property("_certificate_hold") - privilege_withdrawn = utils.read_only_property("_privilege_withdrawn") - aa_compromise = utils.read_only_property("_aa_compromise") +class ReasonFlags(Enum): + unspecified = "unspecified" + key_compromise = "keyCompromise" + ca_compromise = "cACompromise" + affiliation_changed = "affiliationChanged" + superseded = "superseded" + cessation_of_operation = "cessationOfOperation" + certificate_hold = "certificateHold" + privilege_withdrawn = "privilegeWithdrawn" + aa_compromise = "aACompromise" + remove_from_crl = "removeFromCRL" @six.add_metaclass(abc.ABCMeta) diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 1ccb361b..e0858c76 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -1320,69 +1320,46 @@ class TestAuthorityKeyIdentifierExtension(object): assert ext.value.authority_cert_serial_number == 3 -class TestReasonFlags(object): - def test_flags(self): - flags = x509.ReasonFlags( - True, True, False, False, True, True, False, False - ) - assert flags.key_compromise is True - assert flags.ca_compromise is True - assert flags.affiliation_changed is False - assert flags.superseded is False - assert flags.cessation_of_operation is True - assert flags.certificate_hold is True - assert flags.privilege_withdrawn is False - assert flags.aa_compromise is False - - def test_eq(self): - flags = x509.ReasonFlags( - True, True, False, False, True, True, False, False - ) - flags2 = x509.ReasonFlags( - True, True, False, False, True, True, False, False - ) - assert flags == flags2 - - def test_ne(self): - flags = x509.ReasonFlags( - True, True, False, False, True, True, False, False - ) - flags2 = x509.ReasonFlags( - True, True, False, False, True, True, False, True - ) - assert flags != flags2 - assert flags != object() - - def test_repr(self): - flags = x509.ReasonFlags( - True, True, False, False, True, True, False, False - ) - assert repr(flags) == ( - "" - ) - - class TestDistributionPoint(object): - def test_distribution_point_list_not_general_names(self): + def test_distribution_point_full_name_not_general_names(self): with pytest.raises(TypeError): - x509.DistributionPoint(["notgn"], None, None) + x509.DistributionPoint(["notgn"], None, None, None) - def test_distribution_point_not_name(self): + def test_distribution_point_relative_name_not_name(self): with pytest.raises(TypeError): - x509.DistributionPoint("notname", None, None) + x509.DistributionPoint(None, "notname", None, None) + + def test_distribution_point_full_and_relative_not_none(self): + with pytest.raises(ValueError): + x509.DistributionPoint("data", "notname", None, None) def test_crl_issuer_not_general_names(self): with pytest.raises(TypeError): - x509.DistributionPoint(None, None, ["notgn"]) + x509.DistributionPoint(None, None, None, ["notgn"]) def test_reason_not_reasonflags(self): with pytest.raises(TypeError): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], - "notreasonflags", + None, + ["notreasonflags"], + None + ) + + def test_disallowed_reasons(self): + with pytest.raises(ValueError): + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + [x509.ReasonFlags.unspecified], + None + ) + + with pytest.raises(ValueError): + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + [x509.ReasonFlags.remove_from_crl], None ) @@ -1390,18 +1367,16 @@ class TestDistributionPoint(object): with pytest.raises(ValueError): x509.DistributionPoint( None, - x509.ReasonFlags( - True, True, False, False, True, True, False, False - ), + None, + [x509.ReasonFlags.aa_compromise], None ) def test_eq(self): dp = x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], - x509.ReasonFlags( - False, False, False, False, False, True, False, False - ), + None, + [x509.ReasonFlags.superseded], [ x509.DirectoryName( x509.Name([ @@ -1414,9 +1389,8 @@ class TestDistributionPoint(object): ) dp2 = x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], - x509.ReasonFlags( - False, False, False, False, False, True, False, False - ), + None, + [x509.ReasonFlags.superseded], [ x509.DirectoryName( x509.Name([ @@ -1432,9 +1406,10 @@ class TestDistributionPoint(object): def test_ne(self): dp = x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], - x509.ReasonFlags( - False, False, False, False, False, True, False, False - ), + None, + [ + x509.ReasonFlags.superseded, + ], [ x509.DirectoryName( x509.Name([ @@ -1448,6 +1423,7 @@ class TestDistributionPoint(object): dp2 = x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], None, + None, None ) assert dp != dp2 @@ -1455,12 +1431,14 @@ class TestDistributionPoint(object): def test_repr(self): dp = x509.DistributionPoint( + None, x509.Name([ x509.NameAttribute(x509.OID_COMMON_NAME, "myCN") ]), - x509.ReasonFlags( - False, False, False, False, False, True, False, False - ), + [ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ], [ x509.DirectoryName( x509.Name([ @@ -1472,14 +1450,12 @@ class TestDistributionPoint(object): ], ) assert repr(dp) == ( - ", value='myCN')>" - "])>, reasons=, crl_issuer=[, value='Important CA')>])>)>])>" + ", val" + "ue='myCN')>])>, reasons=[, ], crl_issuer" + "=[, value='Important CA')>])>)>])>" ) @@ -1493,13 +1469,16 @@ class TestCRLDistributionPoints(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://domain")], None, + None, None ), x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], - x509.ReasonFlags( - True, True, True, True, True, True, True, True - ), + None, + [ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ], None ), ]) @@ -1508,13 +1487,16 @@ class TestCRLDistributionPoints(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://domain")], None, + None, None ), x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], - x509.ReasonFlags( - True, True, True, True, True, True, True, True - ), + None, + [ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ], None ), ] @@ -1523,37 +1505,41 @@ class TestCRLDistributionPoints(object): cdp = x509.CRLDistributionPoints([ x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], - x509.ReasonFlags( - True, True, True, True, True, True, True, True - ), + None, + [ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ], None ), ]) assert repr(cdp) == ( - "], reasons=, crl" - "_issuer=None)>])>" + "], relative_name=None, reason" + "s=[, ], crl_issuer=None)>])>" ) def test_eq(self): cdp = x509.CRLDistributionPoints([ x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], - x509.ReasonFlags( - True, True, True, True, True, True, True, True - ), + None, + [ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ], [x509.UniformResourceIdentifier(u"uri://thing")], ), ]) cdp2 = x509.CRLDistributionPoints([ x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], - x509.ReasonFlags( - True, True, True, True, True, True, True, True - ), + None, + [ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ], [x509.UniformResourceIdentifier(u"uri://thing")], ), ]) @@ -1563,36 +1549,43 @@ class TestCRLDistributionPoints(object): cdp = x509.CRLDistributionPoints([ x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], - x509.ReasonFlags( - True, True, True, True, True, True, True, True - ), + None, + [ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ], [x509.UniformResourceIdentifier(u"uri://thing")], ), ]) cdp2 = x509.CRLDistributionPoints([ x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain2")], - x509.ReasonFlags( - True, True, True, True, True, True, True, True - ), + None, + [ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ], [x509.UniformResourceIdentifier(u"uri://thing")], ), ]) cdp3 = x509.CRLDistributionPoints([ x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], - x509.ReasonFlags( - True, True, True, True, True, True, True, False - ), + None, + [ + x509.ReasonFlags.key_compromise, + ], [x509.UniformResourceIdentifier(u"uri://thing")], ), ]) cdp4 = x509.CRLDistributionPoints([ x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], - x509.ReasonFlags( - True, True, True, True, True, True, True, True - ), + None, + [ + x509.ReasonFlags.key_compromise, + x509.ReasonFlags.ca_compromise, + ], [x509.UniformResourceIdentifier(u"uri://thing2")], ), ]) -- cgit v1.2.3 From f2c072bf271f1ae0081a58fdf232110cc5af815d Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 9 May 2015 17:04:28 -0500 Subject: update doc language --- docs/x509.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/x509.rst b/docs/x509.rst index 3cf4f905..f9992e20 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -816,15 +816,16 @@ X.509 Extensions :type: list of :class:`GeneralName` instances or None - This field describes methods to retrieve the CRL. If this is not None - then ``relative_name`` must be None. + This field describes methods to retrieve the CRL. At most one of + ``full_name`` or ``relative_name`` will be non-None. .. attribute:: relative_name :type: :class:`Name` or None This field describes methods to retrieve the CRL relative to the CRL - issuer. If this is not None then ``full_name`` must be None. + issuer. At most one of ``full_name`` or ``relative_name`` will be + non-None. .. attribute:: crl_issuer -- cgit v1.2.3 From 3fd0260a3dd110d99c0174c3937aa3d86b0d9ba0 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 9 May 2015 19:46:13 -0500 Subject: switch reasons to frozenset --- docs/x509.rst | 2 +- src/cryptography/x509.py | 6 ++-- tests/test_x509_ext.py | 78 ++++++++++++++++++++++++++---------------------- 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/docs/x509.rst b/docs/x509.rst index f9992e20..86673e3b 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -835,7 +835,7 @@ X.509 Extensions .. attribute:: reasons - :type: list of :class:`ReasonFlags` or None + :type: frozenset of :class:`ReasonFlags` or None The reasons a given distribution point may be used for when performing revocation checks. diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index cee0cc39..dfc0af8c 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -536,10 +536,10 @@ class DistributionPoint(object): "crl_issuer must be None or a list of general names" ) - if reasons and not all( + if reasons and (not isinstance(reasons, frozenset) or not all( isinstance(x, ReasonFlags) for x in reasons - ): - raise TypeError("reasons must be None or list of ReasonFlags") + )): + raise TypeError("reasons must be None or frozenset of ReasonFlags") if reasons and ( ReasonFlags.unspecified in reasons or diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index e0858c76..a18a443b 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -1342,7 +1342,16 @@ class TestDistributionPoint(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], None, - ["notreasonflags"], + frozenset(["notreasonflags"]), + None + ) + + def test_reason_not_frozenset(self): + with pytest.raises(TypeError): + x509.DistributionPoint( + [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], + None, + [x509.ReasonFlags.ca_compromise], None ) @@ -1351,7 +1360,7 @@ class TestDistributionPoint(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], None, - [x509.ReasonFlags.unspecified], + frozenset([x509.ReasonFlags.unspecified]), None ) @@ -1359,7 +1368,7 @@ class TestDistributionPoint(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], None, - [x509.ReasonFlags.remove_from_crl], + frozenset([x509.ReasonFlags.remove_from_crl]), None ) @@ -1368,7 +1377,7 @@ class TestDistributionPoint(object): x509.DistributionPoint( None, None, - [x509.ReasonFlags.aa_compromise], + frozenset([x509.ReasonFlags.aa_compromise]), None ) @@ -1376,7 +1385,7 @@ class TestDistributionPoint(object): dp = x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], None, - [x509.ReasonFlags.superseded], + frozenset([x509.ReasonFlags.superseded]), [ x509.DirectoryName( x509.Name([ @@ -1390,7 +1399,7 @@ class TestDistributionPoint(object): dp2 = x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], None, - [x509.ReasonFlags.superseded], + frozenset([x509.ReasonFlags.superseded]), [ x509.DirectoryName( x509.Name([ @@ -1407,9 +1416,7 @@ class TestDistributionPoint(object): dp = x509.DistributionPoint( [x509.UniformResourceIdentifier(u"http://crypt.og/crl")], None, - [ - x509.ReasonFlags.superseded, - ], + frozenset([x509.ReasonFlags.superseded]), [ x509.DirectoryName( x509.Name([ @@ -1435,10 +1442,10 @@ class TestDistributionPoint(object): x509.Name([ x509.NameAttribute(x509.OID_COMMON_NAME, "myCN") ]), - [ + frozenset([ x509.ReasonFlags.key_compromise, x509.ReasonFlags.ca_compromise, - ], + ]), [ x509.DirectoryName( x509.Name([ @@ -1452,10 +1459,11 @@ class TestDistributionPoint(object): assert repr(dp) == ( ", val" - "ue='myCN')>])>, reasons=[, ], crl_issuer" - "=[, value='Important CA')>])>)>])>" + "ue='myCN')>])>, reasons=frozenset([, ])," + " crl_issuer=[, value='Important C" + "A')>])>)>])>" ) @@ -1475,10 +1483,10 @@ class TestCRLDistributionPoints(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], None, - [ + frozenset([ x509.ReasonFlags.key_compromise, x509.ReasonFlags.ca_compromise, - ], + ]), None ), ]) @@ -1493,10 +1501,10 @@ class TestCRLDistributionPoints(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], None, - [ + frozenset([ x509.ReasonFlags.key_compromise, x509.ReasonFlags.ca_compromise, - ], + ]), None ), ] @@ -1506,18 +1514,18 @@ class TestCRLDistributionPoints(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], None, - [ + frozenset([ x509.ReasonFlags.key_compromise, x509.ReasonFlags.ca_compromise, - ], + ]), None ), ]) assert repr(cdp) == ( "], relative_name=None, reason" - "s=[, ], crl_issuer=None)>])>" + "s=frozenset([, ]), crl_issuer=None)>])>" ) def test_eq(self): @@ -1525,10 +1533,10 @@ class TestCRLDistributionPoints(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], None, - [ + frozenset([ x509.ReasonFlags.key_compromise, x509.ReasonFlags.ca_compromise, - ], + ]), [x509.UniformResourceIdentifier(u"uri://thing")], ), ]) @@ -1536,10 +1544,10 @@ class TestCRLDistributionPoints(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], None, - [ + frozenset([ x509.ReasonFlags.key_compromise, x509.ReasonFlags.ca_compromise, - ], + ]), [x509.UniformResourceIdentifier(u"uri://thing")], ), ]) @@ -1550,10 +1558,10 @@ class TestCRLDistributionPoints(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], None, - [ + frozenset([ x509.ReasonFlags.key_compromise, x509.ReasonFlags.ca_compromise, - ], + ]), [x509.UniformResourceIdentifier(u"uri://thing")], ), ]) @@ -1561,10 +1569,10 @@ class TestCRLDistributionPoints(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain2")], None, - [ + frozenset([ x509.ReasonFlags.key_compromise, x509.ReasonFlags.ca_compromise, - ], + ]), [x509.UniformResourceIdentifier(u"uri://thing")], ), ]) @@ -1572,9 +1580,7 @@ class TestCRLDistributionPoints(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], None, - [ - x509.ReasonFlags.key_compromise, - ], + frozenset([x509.ReasonFlags.key_compromise]), [x509.UniformResourceIdentifier(u"uri://thing")], ), ]) @@ -1582,10 +1588,10 @@ class TestCRLDistributionPoints(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], None, - [ + frozenset([ x509.ReasonFlags.key_compromise, x509.ReasonFlags.ca_compromise, - ], + ]), [x509.UniformResourceIdentifier(u"uri://thing2")], ), ]) -- cgit v1.2.3 From 96ef63c9996612caea7342cf78c0abb57564989c Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sat, 9 May 2015 21:17:04 -0500 Subject: fix repr tests --- tests/test_x509_ext.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index a18a443b..58fb3c46 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -1442,10 +1442,7 @@ class TestDistributionPoint(object): x509.Name([ x509.NameAttribute(x509.OID_COMMON_NAME, "myCN") ]), - frozenset([ - x509.ReasonFlags.key_compromise, - x509.ReasonFlags.ca_compromise, - ]), + frozenset([x509.ReasonFlags.ca_compromise]), [ x509.DirectoryName( x509.Name([ @@ -1459,11 +1456,10 @@ class TestDistributionPoint(object): assert repr(dp) == ( ", val" - "ue='myCN')>])>, reasons=frozenset([, ])," - " crl_issuer=[, value='Important C" - "A')>])>)>])>" + "ue='myCN')>])>, reasons=frozenset([]), crl_issuer=[, v" + "alue='Important CA')>])>)>])>" ) @@ -1514,18 +1510,15 @@ class TestCRLDistributionPoints(object): x509.DistributionPoint( [x509.UniformResourceIdentifier(u"ftp://domain")], None, - frozenset([ - x509.ReasonFlags.key_compromise, - x509.ReasonFlags.ca_compromise, - ]), + frozenset([x509.ReasonFlags.key_compromise]), None ), ]) assert repr(cdp) == ( "], relative_name=None, reason" - "s=frozenset([, ]), crl_issuer=None)>])>" + "s=frozenset([]), crl" + "_issuer=None)>])>" ) def test_eq(self): -- cgit v1.2.3 From 749da3b67c76ca7172eef88b2624b46cb99510a9 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 10 May 2015 09:58:29 -0500 Subject: repr tests are the worst. frozenset has diff repr on py3 --- tests/test_x509_ext.py | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/tests/test_x509_ext.py b/tests/test_x509_ext.py index 58fb3c46..06a68600 100644 --- a/tests/test_x509_ext.py +++ b/tests/test_x509_ext.py @@ -1453,14 +1453,24 @@ class TestDistributionPoint(object): ) ], ) - assert repr(dp) == ( - ", val" - "ue='myCN')>])>, reasons=frozenset([]), crl_issuer=[, v" - "alue='Important CA')>])>)>])>" - ) + if six.PY3: + assert repr(dp) == ( + ", value='myCN')>])>, reasons=frozenset({}), crl_issuer=[, value='Important CA')>])>)>])>" + ) + else: + assert repr(dp) == ( + ", value='myCN')>])>, reasons=frozenset([]), crl_issuer=[, value='Important CA')>])>)>])>" + ) class TestCRLDistributionPoints(object): @@ -1514,12 +1524,20 @@ class TestCRLDistributionPoints(object): None ), ]) - assert repr(cdp) == ( - "], relative_name=None, reason" - "s=frozenset([]), crl" - "_issuer=None)>])>" - ) + if six.PY3: + assert repr(cdp) == ( + "], relative_name=No" + "ne, reasons=frozenset({}), crl_issuer=None)>])>" + ) + else: + assert repr(cdp) == ( + "], relative_name=No" + "ne, reasons=frozenset([]), crl_issuer=None)>])>" + ) def test_eq(self): cdp = x509.CRLDistributionPoints([ -- cgit v1.2.3