diff options
-rw-r--r-- | docs/x509.rst | 71 | ||||
-rw-r--r-- | src/cryptography/x509.py | 73 | ||||
-rw-r--r-- | tests/test_x509.py | 47 |
3 files changed, 191 insertions, 0 deletions
diff --git a/docs/x509.rst b/docs/x509.rst index 26b91873..525b869b 100644 --- a/docs/x509.rst +++ b/docs/x509.rst @@ -181,6 +181,71 @@ X.509 Certificate Object For version 3 X.509 certificates. +.. class:: Attribute + + .. versionadded:: 0.8 + + .. attribute:: oid + + :type: :class:`ObjectIdentifier` + + The attribute OID. + + .. attribute:: value + + :type: :class:`str` + + The value of the attribute. + +.. class:: ObjectIdentifier + + .. versionadded:: 0.8 + + .. attribute:: value + + :type: :class:`str` + + The dotted string value of the OID (e.g. "2.5.4.3") + +Object Identifiers +~~~~~~~~~~~~~~~~~~ + +X.509 name elements are identified by :class:`ObjectIdentifier` instances. The +following common OIDs are available as constants. + +.. data:: OID_COMMON_NAME + +.. data:: OID_COUNTRY_NAME + +.. data:: OID_LOCALITY_NAME + +.. data:: OID_STATE_OR_PROVINCE_NAME + +.. data:: OID_ORGANIZATION_NAME + +.. data:: OID_ORGANIZATIONAL_UNIT_NAME + +.. data:: OID_SERIAL_NUMBER + +.. data:: OID_SURNAME + +.. data:: OID_GIVEN_NAME + +.. data:: OID_TITLE + +.. data:: OID_GENERATION_QUALIFIER + +.. data:: OID_DN_QUALIFIER + +.. data:: OID_PSEUDONYM + +.. data:: OID_DOMAIN_COMPONENT + +.. data:: OID_EMAIL_ADDRESS + +Exceptions +~~~~~~~~~~ + .. class:: InvalidVersion This is raised when an X.509 certificate has an invalid version number. @@ -191,6 +256,12 @@ X.509 Certificate Object Returns the raw version that was parsed from the certificate. +.. class:: UnknownAttribute + + This is raised when an X.509 certificate has an unknown attribute in a + distinguished name. + + .. _`public key infrastructure`: https://en.wikipedia.org/wiki/Public_key_infrastructure .. _`TLS`: https://en.wikipedia.org/wiki/Transport_Layer_Security diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index be1298b6..8cdf7db5 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -9,6 +9,8 @@ from enum import Enum import six +from cryptography import utils + class Version(Enum): v1 = 0 @@ -29,6 +31,77 @@ class InvalidVersion(Exception): self.parsed_version = parsed_version +class UnknownAttribute(Exception): + pass + + +class Attribute(object): + def __init__(self, oid, value): + if not isinstance(oid, ObjectIdentifier): + raise TypeError("oid argument must be an ObjectIdentifier object") + + self._oid = oid + self._value = value + + oid = utils.read_only_property("_oid") + value = utils.read_only_property("_value") + + def __eq__(self, other): + if not isinstance(other, Attribute): + return NotImplemented + + return ( + self.oid == other.oid and + self.value == other.value + ) + + def __ne__(self, other): + return not self == other + + +class ObjectIdentifier(object): + def __init__(self, oid, name): + self._value = oid + self._name = name + + def __eq__(self, other): + if not isinstance(other, ObjectIdentifier): + return NotImplemented + + return self._value == other._value and self._name == other._name + + def __ne__(self, other): + return not self == other + + def __repr__(self): + return "<ObjectIdentifier(oid={0}, name={1})>".format( + self._value, self._name + ) + + value = utils.read_only_property("_value") + + +OID_COMMON_NAME = ObjectIdentifier("2.5.4.3", "commonName") +OID_COUNTRY_NAME = ObjectIdentifier("2.5.4.6", "countryName") +OID_LOCALITY_NAME = ObjectIdentifier("2.5.4.7", "localityName") +OID_STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8", "stateOrProvinceName") +OID_ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10", "organizationName") +OID_ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier( + "2.5.4.11", "organizationalUnitName" +) +OID_SERIAL_NUMBER = ObjectIdentifier("2.5.4.5", "serialNumber") +OID_SURNAME = ObjectIdentifier("2.5.4.4", "surname") +OID_GIVEN_NAME = ObjectIdentifier("2.5.4.42", "givenName") +OID_TITLE = ObjectIdentifier("2.5.4.12", "title") +OID_GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44", "generationQualifier") +OID_DN_QUALIFIER = ObjectIdentifier("2.5.4.46", "dnQualifier") +OID_PSEUDONYM = ObjectIdentifier("2.5.4.65", "pseudonym") +OID_DOMAIN_COMPONENT = ObjectIdentifier( + "0.9.2342.19200300.100.1.25", "domainComponent" +) +OID_EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1", "emailAddress") + + @six.add_metaclass(abc.ABCMeta) class Certificate(object): @abc.abstractmethod diff --git a/tests/test_x509.py b/tests/test_x509.py index 5383871a..f8066699 100644 --- a/tests/test_x509.py +++ b/tests/test_x509.py @@ -248,3 +248,50 @@ class TestECDSACertificate(object): ) with pytest.raises(NotImplementedError): cert.public_key() + + +class TestAttribute(object): + def test_eq(self): + assert x509.Attribute( + x509.ObjectIdentifier('oid', 'name'), 'value' + ) == x509.Attribute( + x509.ObjectIdentifier('oid', 'name'), 'value' + ) + + def test_ne(self): + assert x509.Attribute( + x509.ObjectIdentifier('oid', 'name'), 'value' + ) != x509.Attribute( + x509.ObjectIdentifier('oid2', 'name'), 'value' + ) + assert x509.Attribute( + x509.ObjectIdentifier('oid', 'name'), 'value' + ) != x509.Attribute( + x509.ObjectIdentifier('oid', 'name2'), 'value' + ) + assert x509.Attribute( + x509.ObjectIdentifier('oid', 'name'), 'value' + ) != x509.Attribute( + x509.ObjectIdentifier('oid', 'name'), 'value2' + ) + assert x509.Attribute( + x509.ObjectIdentifier('oid', 'name'), 'value' + ) != object() + + +class TestObjectIdentifier(object): + def test_eq(self): + oid1 = x509.ObjectIdentifier('oid', 'name') + oid2 = x509.ObjectIdentifier('oid', 'name') + assert oid1 == oid2 + + def test_ne(self): + oid1 = x509.ObjectIdentifier('oid', 'name') + assert oid1 != x509.ObjectIdentifier('oid1', 'name') + assert oid1 != x509.ObjectIdentifier('oid', 'name1') + assert oid1 != x509.ObjectIdentifier('oid1', 'name1') + assert oid1 != object() + + def test_repr(self): + oid = x509.ObjectIdentifier("oid1", "name") + assert repr(oid) == "<ObjectIdentifier(oid=oid1, name=name)>" |