diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-05-06 00:29:12 -0500 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-05-06 01:02:19 -0500 |
commit | 5a48552b4b7fc4d108b6d45232769f111fe38896 (patch) | |
tree | abf09f624ff61b0bc92759937c6e9ae8ede96996 | |
parent | c86fd1db1f8b459b720c62bdb94e7d9fb5c3b8be (diff) | |
download | cryptography-5a48552b4b7fc4d108b6d45232769f111fe38896.tar.gz cryptography-5a48552b4b7fc4d108b6d45232769f111fe38896.tar.bz2 cryptography-5a48552b4b7fc4d108b6d45232769f111fe38896.zip |
add CRLDistributionPoints and associated classes
-rw-r--r-- | docs/x509.rst | 72 | ||||
-rw-r--r-- | src/cryptography/x509.py | 144 | ||||
-rw-r--r-- | tests/test_x509_ext.py | 282 |
3 files changed, 498 insertions, 0 deletions
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 "<CRLDistributionPoints({0})>".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 ( + "<DistributionPoint(distribution_point={0.distribution_point}, rea" + "sons={0.reasons}, crl_issuer={0.crl_issuer})>".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 ( + "<ReasonFlags(key_compromise={0.key_compromise}, ca_compromise" + "={0.ca_compromise}, affiliation_changed={0.affiliation_changed}," + "superseded={0.superseded}, cessation_of_operation={0.cessation_o" + "f_operation}, certificate_hold={0.certificate_hold}, privilege_w" + "ithdrawn={0.privilege_withdrawn}, aa_compromise={0.aa_compromise" + "})>".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) == ( + "<ReasonFlags(key_compromise=True, ca_compromise=True, affiliatio" + "n_changed=False,superseded=False, cessation_of_operation=True, c" + "ertificate_hold=True, privilege_withdrawn=False, aa_compromise=F" + "alse)>" + ) + + +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) == ( + "<DistributionPoint(distribution_point=<Name([<NameAttribute(oid=" + "<ObjectIdentifier(oid=2.5.4.3, name=commonName)>, value='myCN')>" + "])>, reasons=<ReasonFlags(key_compromise=False, ca_compromise=Fa" + "lse, affiliation_changed=False,superseded=False, cessation_of_op" + "eration=False, certificate_hold=True, privilege_withdrawn=False," + " aa_compromise=False)>, crl_issuer=[<DirectoryName(value=<Name([" + "<NameAttribute(oid=<ObjectIdentifier(oid=2.5.4.3, name=commonNam" + "e)>, 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) == ( + "<CRLDistributionPoints([<DistributionPoint(distribution_point=[<" + "UniformResourceIdentifier(value=ftp://domain)>], reasons=<Reason" + "Flags(key_compromise=True, ca_compromise=True, affiliation_chang" + "ed=True,superseded=True, cessation_of_operation=True, certificat" + "e_hold=True, privilege_withdrawn=True, aa_compromise=True)>, 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() |