Get all the X509Name tests passing
diff --git a/OpenSSL/crypto.py b/OpenSSL/crypto.py
index 94f7d58..58990d6 100644
--- a/OpenSSL/crypto.py
+++ b/OpenSSL/crypto.py
@@ -117,6 +117,165 @@
 
 
 
+class X509Name(object):
+    def __init__(self, name):
+        """
+        Create a new X509Name, copying the given X509Name instance.
+
+        :param name: An X509Name object to copy
+        """
+        self._name = _api.X509_NAME_dup(name._name)
+
+
+    def __setattr__(self, name, value):
+        if name.startswith('_'):
+            return super(X509Name, self).__setattr__(name, value)
+
+        if type(name) is not str:
+            raise TypeError("attribute name must be string, not '%.200s'" % (
+                    type(value).__name__,))
+
+        nid = _api.OBJ_txt2nid(name)
+        if nid == _api.NID_undef:
+            try:
+                _raise_current_error()
+            except Error:
+                pass
+            raise AttributeError("No such attribute")
+
+        # If there's an old entry for this NID, remove it
+        for i in range(_api.X509_NAME_entry_count(self._name)):
+            ent = _api.X509_NAME_get_entry(self._name, i)
+            ent_obj = _api.X509_NAME_ENTRY_get_object(ent)
+            ent_nid = _api.OBJ_obj2nid(ent_obj)
+            if nid == ent_nid:
+                ent = _api.X509_NAME_delete_entry(self._name, i)
+                _api.X509_NAME_ENTRY_free(ent)
+                break
+
+        if isinstance(value, unicode):
+            value = value.encode('utf-8')
+
+        add_result = _api.X509_NAME_add_entry_by_NID(
+            self._name, nid, _api.MBSTRING_UTF8, value, -1, -1, 0)
+        if not add_result:
+            # TODO Untested
+            1/0
+
+
+    def __getattr__(self, name):
+        """
+        Find attribute. An X509Name object has the following attributes:
+        countryName (alias C), stateOrProvince (alias ST), locality (alias L),
+        organization (alias O), organizationalUnit (alias OU), commonName (alias
+        CN) and more...
+        """
+        nid = _api.OBJ_txt2nid(name)
+        if nid == _api.NID_undef:
+            # This is a bit weird.  OBJ_txt2nid indicated failure, but it seems
+            # a lower level function, a2d_ASN1_OBJECT, also feels the need to
+            # push something onto the error queue.  If we don't clean that up
+            # now, someone else will bump into it later and be quite confused.
+            # See lp#314814.
+            try:
+                _raise_current_error()
+            except Error:
+                pass
+            return super(X509Name, self).__getattr__(name)
+
+        entry_index = _api.X509_NAME_get_index_by_NID(self._name, nid, -1)
+        if entry_index == -1:
+            return None
+
+        entry = _api.X509_NAME_get_entry(self._name, entry_index)
+        data = _api.X509_NAME_ENTRY_get_data(entry)
+
+        result_buffer = _api.new("unsigned char**")
+        data_length = _api.ASN1_STRING_to_UTF8(result_buffer, data)
+        if data_length < 0:
+            1/0
+
+        result = _api.buffer(result_buffer[0], data_length)[:].decode('utf-8')
+        _api.OPENSSL_free(result_buffer[0])
+        return result
+
+
+    def __cmp__(self, other):
+        if not isinstance(other, X509Name):
+            return NotImplemented
+
+        result = _api.X509_NAME_cmp(self._name, other._name)
+        # TODO result == -2 is an error case that maybe should be checked for
+        return result
+
+
+    def __repr__(self):
+        """
+        String representation of an X509Name
+        """
+        result_buffer = _api.new("char[]", 512);
+        format_result = _api.X509_NAME_oneline(
+            self._name, result_buffer, len(result_buffer))
+
+        if format_result == _api.NULL:
+            1/0
+
+        return "<X509Name object '%s'>" % (_api.string(result_buffer),)
+
+
+    def hash(self):
+        """
+        Return the hash value of this name
+
+        :return: None
+        """
+        return _api.X509_NAME_hash(self._name)
+
+
+    def der(self):
+        """
+        Return the DER encoding of this name
+
+        :return: A :py:class:`bytes` instance giving the DER encoded form of
+            this name.
+        """
+        result_buffer = _api.new('unsigned char**')
+        encode_result = _api.i2d_X509_NAME(self._name, result_buffer)
+        if encode_result < 0:
+            1/0
+
+        string_result = _api.buffer(result_buffer[0], encode_result)[:]
+        _api.OPENSSL_free(result_buffer[0])
+        return string_result
+
+
+    def get_components(self):
+        """
+        Returns the split-up components of this name.
+
+        :return: List of tuples (name, value).
+        """
+        result = []
+        for i in range(_api.X509_NAME_entry_count(self._name)):
+            ent = _api.X509_NAME_get_entry(self._name, i)
+
+            fname = _api.X509_NAME_ENTRY_get_object(ent)
+            fval = _api.X509_NAME_ENTRY_get_data(ent)
+
+            nid = _api.OBJ_obj2nid(fname)
+            name = _api.OBJ_nid2sn(nid)
+
+            result.append((
+                    _api.string(name),
+                    _api.string(
+                        _api.ASN1_STRING_data(fval),
+                        _api.ASN1_STRING_length(fval))))
+
+        return result
+X509NameType = X509Name
+
+
+
 class X509(object):
     def __init__(self):
         # TODO Allocation failure?  And why not __new__ instead of __init__?
@@ -421,6 +580,32 @@
         """
         notAfter = _api.X509_get_notAfter(self._x509)
         _api.ASN1_GENERALIZEDTIME_set_string(notAfter, when)
+
+
+    def get_subject(self):
+        """
+        Create an X509Name object for the subject of the certificate
+
+        :return: An X509Name object
+        """
+        name = X509Name.__new__(X509Name)
+        name._name = _api.X509_get_subject_name(self._x509)
+        if name._name == _api.NULL:
+            1/0
+        return name
+
+
+    def set_subject(self, subject):
+        """
+        Set the subject of the certificate
+
+        :param subject: The subject name
+        :type subject: :py:class:`X509Name`
+        :return: None
+        """
+        set_result = _api.X509_set_subject_name(self._x509, subject._name)
+        if not set_result:
+            1/0
 X509Type = X509