add attribute and objectidentifier classes for x509 name
diff --git a/docs/x509.rst b/docs/x509.rst
index 26b9187..525b869 100644
--- a/docs/x509.rst
+++ b/docs/x509.rst
@@ -181,6 +181,71 @@
 
         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 @@
 
         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 be1298b..8cdf7db 100644
--- a/src/cryptography/x509.py
+++ b/src/cryptography/x509.py
@@ -9,6 +9,8 @@
 
 import six
 
+from cryptography import utils
+
 
 class Version(Enum):
     v1 = 0
@@ -29,6 +31,77 @@
         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 5383871..f806669 100644
--- a/tests/test_x509.py
+++ b/tests/test_x509.py
@@ -248,3 +248,50 @@
         )
         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)>"