Switch from tp_setattr to tp_setattro, since PyPy does not support the former; also fix an error case which affects CPython too, where an unknown attribute is set on an X509Name
diff --git a/OpenSSL/crypto/x509name.c b/OpenSSL/crypto/x509name.c
index d0dfb91..4ff2c34 100644
--- a/OpenSSL/crypto/x509name.c
+++ b/OpenSSL/crypto/x509name.c
@@ -195,14 +195,24 @@
  *            value - The value to set
  */
 static int
-crypto_X509Name_setattr(crypto_X509NameObj *self, char *name, PyObject *value)
+crypto_X509Name_setattro(crypto_X509NameObj *self, PyObject *nameobj, PyObject *value)
 {
     int nid;
     int result;
     char *buffer;
+    char *name;
+
+    if (!PyString_CheckExact(nameobj) || !(name = PyString_AsString(nameobj))) {
+        PyErr_Format(PyExc_TypeError,
+                     "attribute name must be string, not '%.200s'",
+                     Py_TYPE(nameobj)->tp_name);
+        return -1;
+    }
 
     if ((nid = OBJ_txt2nid(name)) == NID_undef)
     {
+        /* Just like the case in the getattr function */
+        flush_error_queue();
         PyErr_SetString(PyExc_AttributeError, "No such attribute");
         return -1;
     }
@@ -475,7 +485,7 @@
     (destructor)crypto_X509Name_dealloc,
     NULL, /* print */
     NULL, /* getattr */
-    (setattrfunc)crypto_X509Name_setattr,
+    NULL, /* setattr */
     NULL, /* reserved */
     (reprfunc)crypto_X509Name_repr,
     NULL, /* as_number */
@@ -485,7 +495,7 @@
     NULL, /* call */
     NULL, /* str */
     (getattrofunc)crypto_X509Name_getattro, /* getattro */
-    NULL, /* setattro */
+    (setattrofunc)crypto_X509Name_setattro, /* setattro */
     NULL, /* as_buffer */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
     crypto_X509Name_doc, /* tp_doc */
diff --git a/OpenSSL/test/test_crypto.py b/OpenSSL/test/test_crypto.py
index 661ee53..3d17767 100644
--- a/OpenSSL/test/test_crypto.py
+++ b/OpenSSL/test/test_crypto.py
@@ -618,6 +618,33 @@
                 name, type(name), X509NameType))
 
 
+    def test_onlyStringAttributes(self):
+        """
+        Attempting to set a non-L{str} attribute name on an L{X509NameType}
+        instance causes L{TypeError} to be raised.
+        """
+        name = self._x509name()
+        # Beyond these cases, you may also think that unicode should be
+        # rejected.  Sorry, you're wrong.  unicode is automatically converted to
+        # str outside of the control of X509Name, so there's no way to reject
+        # it.
+        self.assertRaises(TypeError, setattr, name, None, "hello")
+        self.assertRaises(TypeError, setattr, name, 30, "hello")
+        class evil(str):
+            pass
+        self.assertRaises(TypeError, setattr, name, evil(), "hello")
+
+
+    def test_setInvalidAttribute(self):
+        """
+        Attempting to set any attribute name on an L{X509NameType} instance for
+        which no corresponding NID is defined causes L{AttributeError} to be
+        raised.
+        """
+        name = self._x509name()
+        self.assertRaises(AttributeError, setattr, name, "no such thing", None)
+
+
     def test_attributes(self):
         """
         L{X509NameType} instances have attributes for each standard (?)