Add client ca stuff
diff --git a/doc/pyOpenSSL.tex b/doc/pyOpenSSL.tex
index cea48e9..cedeccb 100644
--- a/doc/pyOpenSSL.tex
+++ b/doc/pyOpenSSL.tex
@@ -189,8 +189,8 @@
 \end{datadesc}
 
 \begin{classdesc}{X509Extension}{typename, critical, value\optional{, subject}\optional{, issuer}}
-A class representing an X.509 v3 certificate extensions.  
-See \url{http://openssl.org/docs/apps/x509v3_config.html\#STANDARD_EXTENSIONS} 
+A class representing an X.509 v3 certificate extensions.
+See \url{http://openssl.org/docs/apps/x509v3_config.html\#STANDARD_EXTENSIONS}
 for \var{typename} strings and their options.
 Optional parameters \var{subject} and \var{issuer} must be X509 objects.
 \end{classdesc}
@@ -673,7 +673,7 @@
 \end{funcdesc}
 
 \begin{excdesc}{Error}
-If the current RAND method supports any errors, this is raised when needed.  
+If the current RAND method supports any errors, this is raised when needed.
 The default method does not raise this when the entropy pool is depleted.
 
 Whenever this exception is raised directly, it has a list of error messages
@@ -853,6 +853,22 @@
 when requesting a client certificate.
 \end{methoddesc}
 
+\begin{methoddesc}[Context]{set_client_ca_list}{certificate_authorities}
+Replace the current list of preferred certificate signers that would be
+sent to the client when requesting a client certificate with the
+\var{certificate_authorities} sequence of \class{OpenSSL.crypto.X509Name}s.
+
+\versionadded{0.10}
+\end{methoddesc}
+
+\begin{methoddesc}[Context]{add_client_ca}{certificate_authority}
+Extract a \class{OpenSSL.crypto.X509Name} from the \var{certificate_authority}
+\class{OpenSSL.crypto.X509} certificate and add it to the list of preferred
+certificate signers sent to the client when requesting a client certificate.
+
+\versionadded{0.10}
+\end{methoddesc}
+
 \begin{methoddesc}[Context]{load_verify_locations}{pemfile, capath}
 Specify where CA certificates for verification purposes are located. These
 are trusted certificates. Note that the certificates have to be in PEM
@@ -1026,6 +1042,20 @@
 but not it returns the entire list in one go.
 \end{methoddesc}
 
+\begin{methoddesc}[Connection]{get_client_ca_list}{}
+Retrieve the list of preferred client certificate issuers sent by the server
+as \class{OpenSSL.crypto.X509Name} objects.
+
+If this is a client \class{Connection}, the list will be empty until the
+connection with the server is established.
+
+If this is a server \class{Connection}, return the list of certificate
+authorities that will be sent or has been sent to the client, as controlled
+by this \class{Connection}'s \class{Context}.
+
+\versionadded{0.10}
+\end{methoddesc}
+
 \begin{methoddesc}[Connection]{get_context}{}
 Retrieve the Context object associated with this Connection.
 \end{methoddesc}
diff --git a/src/ssl/connection.c b/src/ssl/connection.c
index e10989b..1c59ff3 100755
--- a/src/ssl/connection.c
+++ b/src/ssl/connection.c
@@ -829,6 +829,59 @@
     return lst;
 }
 
+static char ssl_Connection_get_client_ca_list_doc[] = "\n\
+Get CAs whose certificates are suggested for client authentication.\n\
+\n\
+@return: If this is a server connection, a list of X509Names representing\n\
+    the acceptable CAs as set by L{OpenSSL.SSL.Context.set_client_ca_list} or\n\
+    L{OpenSSL.SSL.Context.add_client_ca}.  If this is a client connection,\n\
+    the list of such X509Names sent by the server, or an empty list if that\n\
+    has not yet happened.\n\
+";
+
+static PyObject *
+ssl_Connection_get_client_ca_list(ssl_ConnectionObj *self, PyObject *args) {
+    STACK_OF(X509_NAME) *CANames;
+    PyObject *CAList;
+    int i, n;
+
+    if (!PyArg_ParseTuple(args, ":get_client_ca_list")) {
+        return NULL;
+    }
+    CANames = SSL_get_client_CA_list(self->ssl);
+    if (CANames == NULL) {
+        return PyList_New(0);
+    }
+    n = sk_X509_NAME_num(CANames);
+    CAList = PyList_New(n);
+    if (CAList == NULL) {
+        return NULL;
+    }
+    for (i = 0; i < n; i++) {
+        X509_NAME *CAName;
+        PyObject *CA;
+
+        CAName = X509_NAME_dup(sk_X509_NAME_value(CANames, i));
+        if (CAName == NULL) {
+            Py_DECREF(CAList);
+            exception_from_error_queue(ssl_Error);
+            return NULL;
+        }
+        CA = (PyObject *)crypto_X509Name_New(CAName, 1);
+        if (CA == NULL) {
+            X509_NAME_free(CAName);
+            Py_DECREF(CAList);
+            return NULL;
+        }
+        if (PyList_SetItem(CAList, i, CA)) {
+            Py_DECREF(CA);
+            Py_DECREF(CAList);
+            return NULL;
+        }
+    }
+    return CAList;
+}
+
 static char ssl_Connection_makefile_doc[] = "\n\
 The makefile() method is not implemented, since there is no dup semantics\n\
 for SSL connections\n\
@@ -1087,6 +1140,7 @@
     ADD_METHOD(bio_shutdown),
     ADD_METHOD(shutdown),
     ADD_METHOD(get_cipher_list),
+    ADD_METHOD(get_client_ca_list),
     ADD_METHOD(makefile),
     ADD_METHOD(get_app_data),
     ADD_METHOD(set_app_data),
diff --git a/src/ssl/context.c b/src/ssl/context.c
index df7411f..ebaf164 100644
--- a/src/ssl/context.c
+++ b/src/ssl/context.c
@@ -13,8 +13,10 @@
 
 #if PY_VERSION_HEX >= 0x02050000
 # define PYARG_PARSETUPLE_FORMAT const char
+# define PYOBJECT_GETATTRSTRING_TYPE const char*
 #else
 # define PYARG_PARSETUPLE_FORMAT char
+# define PYOBJECT_GETATTRSTRING_TYPE char*
 #endif
 
 #ifndef MS_WINDOWS
@@ -335,37 +337,64 @@
     return Py_None;
 }
 
+static PyTypeObject *
+type_modified_error(const char *name) {
+    PyErr_Format(PyExc_RuntimeError,
+                 "OpenSSL.crypto's '%s' attribute has been modified",
+                 name);
+    return NULL;
+}
+
+static PyTypeObject *
+import_crypto_type(const char *name, size_t objsize) {
+    PyObject *module, *type, *name_attr;
+    PyTypeObject *res;
+    int right_name;
+
+    module = PyImport_ImportModule("OpenSSL.crypto");
+    if (module == NULL) {
+        return NULL;
+    }
+    type = PyObject_GetAttrString(module, (PYOBJECT_GETATTRSTRING_TYPE)name);
+    Py_DECREF(module);
+    if (type == NULL) {
+        return NULL;
+    }
+    if (!(PyType_Check(type))) {
+        Py_DECREF(type);
+        return type_modified_error(name);
+    }
+    name_attr = PyObject_GetAttrString(type, "__name__");
+    if (name_attr == NULL) {
+        Py_DECREF(type);
+        return NULL;
+    }
+    right_name = (PyString_CheckExact(name_attr) &&
+                  strcmp(name, PyString_AsString(name_attr)) == 0);
+    Py_DECREF(name_attr);
+    res = (PyTypeObject *)type;
+    if (!right_name || res->tp_basicsize != objsize) {
+        Py_DECREF(type);
+        return type_modified_error(name);
+    }
+    return res;
+}
+
 static crypto_X509Obj *
-parse_certificate_argument(const char* format1, const char* format2, PyObject* args)
-{
+parse_certificate_argument(const char* format, PyObject* args) {
     static PyTypeObject *crypto_X509_type = NULL;
     crypto_X509Obj *cert;
 
-    /* We need to check that cert really is an X509 object before
-       we deal with it. The problem is we can't just quickly verify
-       the type (since that comes from another module). This should
-       do the trick (reasonably well at least): Once we have one
-       verified object, we use it's type object for future
-       comparisons. */
-
-    if (!crypto_X509_type)
-    {
-	if (!PyArg_ParseTuple(args, (PYARG_PARSETUPLE_FORMAT *)format1, &cert))
-	    return NULL;
-
-	if (strcmp(cert->ob_type->tp_name, "X509") != 0 || 
-	    cert->ob_type->tp_basicsize != sizeof(crypto_X509Obj))
-	{
-	    PyErr_SetString(PyExc_TypeError, "Expected an X509 object");
-	    return NULL;
-	}
-
-	crypto_X509_type = cert->ob_type;
+    if (!crypto_X509_type) {
+        crypto_X509_type = import_crypto_type("X509", sizeof(crypto_X509Obj));
+        if (!crypto_X509_type) {
+            return NULL;
+        }
     }
-    else
-	if (!PyArg_ParseTuple(args, (PYARG_PARSETUPLE_FORMAT *)format2, crypto_X509_type,
-			      &cert))
-	    return NULL;
+    if (!PyArg_ParseTuple(args, (PYARG_PARSETUPLE_FORMAT *)format,
+                          crypto_X509_type, &cert)) {
+        return NULL;
+    }
     return cert;
 }
 
@@ -381,7 +410,7 @@
 {
     X509* cert_original;
     crypto_X509Obj *cert = parse_certificate_argument(
-        "O:add_extra_chain_cert", "O!:add_extra_chain_cert", args);
+        "O!:add_extra_chain_cert", args);
     if (cert == NULL)
     {
         return NULL;
@@ -471,7 +500,7 @@
 ssl_Context_use_certificate(ssl_ContextObj *self, PyObject *args)
 {
     crypto_X509Obj *cert = parse_certificate_argument(
-        "O:use_certificate", "O!:use_certificate", args);
+        "O!:use_certificate", args);
     if (cert == NULL) {
         return NULL;
     }
@@ -533,43 +562,24 @@
 @return: None\n\
 ";
 static PyObject *
-ssl_Context_use_privatekey(ssl_ContextObj *self, PyObject *args)
-{
+ssl_Context_use_privatekey(ssl_ContextObj *self, PyObject *args) {
     static PyTypeObject *crypto_PKey_type = NULL;
     crypto_PKeyObj *pkey;
 
-    /* We need to check that cert really is a PKey object before
-       we deal with it. The problem is we can't just quickly verify
-       the type (since that comes from another module). This should
-       do the trick (reasonably well at least): Once we have one
-       verified object, we use it's type object for future
-       comparisons. */
-
-    if (!crypto_PKey_type)
-    {
-	if (!PyArg_ParseTuple(args, "O:use_privatekey", &pkey))
-	    return NULL;
-
-	if (strcmp(pkey->ob_type->tp_name, "OpenSSL.crypto.PKey") != 0 ||
-	    pkey->ob_type->tp_basicsize != sizeof(crypto_PKeyObj))
-	{
-	    PyErr_SetString(PyExc_TypeError, "Expected a PKey object");
-	    return NULL;
-	}
-
-	crypto_PKey_type = pkey->ob_type;
+    if (!crypto_PKey_type) {
+        crypto_PKey_type = import_crypto_type("PKey", sizeof(crypto_PKeyObj));
+        if (!crypto_PKey_type) {
+            return NULL;
+        }
     }
-    else
-    if (!PyArg_ParseTuple(args, "O!:use_privatekey", crypto_PKey_type, &pkey))
+    if (!PyArg_ParseTuple(args, "O!:use_privatekey", crypto_PKey_type, &pkey)) {
         return NULL;
+    }
 
-    if (!SSL_CTX_use_PrivateKey(self->ctx, pkey->pkey))
-    {
+    if (!SSL_CTX_use_PrivateKey(self->ctx, pkey->pkey)) {
         exception_from_error_queue(ssl_Error);
         return NULL;
-    }
-    else
-    {
+    } else {
         Py_INCREF(Py_None);
         return Py_None;
     }
@@ -789,6 +799,111 @@
     }
 }
 
+static char ssl_Context_set_client_ca_list_doc[] = "\n\
+Set the list of preferred client certificate signers for this server context.\n\
+\n\
+This list of certificate authorities will be sent to the client when the\n\
+server requests a client certificate.\n\
+\n\
+@param certificate_authorities: a sequence of X509Names.\n\
+@return: None\n\
+";
+
+static PyObject *
+ssl_Context_set_client_ca_list(ssl_ContextObj *self, PyObject *args)
+{
+    static PyTypeObject *X509NameType;
+    PyObject *sequence, *tuple, *item;
+    crypto_X509NameObj *name;
+    X509_NAME *sslname;
+    STACK_OF(X509_NAME) *CANames;
+    Py_ssize_t length;
+    int i;
+
+    if (X509NameType == NULL) {
+        X509NameType = import_crypto_type("X509Name", sizeof(crypto_X509NameObj));
+        if (X509NameType == NULL) {
+            return NULL;
+        }
+    }
+    if (!PyArg_ParseTuple(args, "O:set_client_ca_list", &sequence)) {
+        return NULL;
+    }
+    tuple = PySequence_Tuple(sequence);
+    if (tuple == NULL) {
+        return NULL;
+    }
+    length = PyTuple_Size(tuple);
+    if (length >= INT_MAX) {
+        PyErr_SetString(PyExc_ValueError, "client CA list is too long");
+        Py_DECREF(tuple);
+        return NULL;
+    }
+    CANames = sk_X509_NAME_new_null();
+    if (CANames == NULL) {
+        Py_DECREF(tuple);
+        exception_from_error_queue(ssl_Error);
+        return NULL;
+    }
+    for (i = 0; i < length; i++) {
+        item = PyTuple_GetItem(tuple, i);
+        if (item->ob_type != X509NameType) {
+            PyErr_Format(PyExc_TypeError,
+                         "client CAs must be X509Name objects, not %s objects",
+                         item->ob_type->tp_name);
+            sk_X509_NAME_free(CANames);
+            Py_DECREF(tuple);
+            return NULL;
+        }
+        name = (crypto_X509NameObj *)item;
+        sslname = X509_NAME_dup(name->x509_name);
+        if (sslname == NULL) {
+            sk_X509_NAME_free(CANames);
+            Py_DECREF(tuple);
+            exception_from_error_queue(ssl_Error);
+            return NULL;
+        }
+        if (!sk_X509_NAME_push(CANames, sslname)) {
+            X509_NAME_free(sslname);
+            sk_X509_NAME_free(CANames);
+            Py_DECREF(tuple);
+            exception_from_error_queue(ssl_Error);
+            return NULL;
+        }
+    }
+    Py_DECREF(tuple);
+    SSL_CTX_set_client_CA_list(self->ctx, CANames);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static char ssl_Context_add_client_ca_doc[] = "\n\
+Add the CA certificate to the list of preferred signers for this context.\n\
+\n\
+The list of certificate authorities will be sent to the client when the\n\
+server requests a client certificate.\n\
+\n\
+@param certificate_authority: certificate authority's X509 certificate.\n\
+@return: None\n\
+";
+
+static PyObject *
+ssl_Context_add_client_ca(ssl_ContextObj *self, PyObject *args)
+{
+    crypto_X509Obj *cert;
+
+    cert = parse_certificate_argument("O!:add_client_ca", args);
+    if (cert == NULL) {
+        return NULL;
+    }
+    if (!SSL_CTX_add_client_CA(self->ctx, cert->x509)) {
+        exception_from_error_queue(ssl_Error);
+        return NULL;
+    }
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
 static char ssl_Context_set_timeout_doc[] = "\n\
 Set session timeout\n\
 \n\
@@ -960,6 +1075,8 @@
     ADD_METHOD(get_verify_depth),
     ADD_METHOD(load_tmp_dh),
     ADD_METHOD(set_cipher_list),
+    ADD_METHOD(set_client_ca_list),
+    ADD_METHOD(add_client_ca),
     ADD_METHOD(set_timeout),
     ADD_METHOD(get_timeout),
     ADD_METHOD(set_info_callback),
diff --git a/src/util.h b/src/util.h
index d9dc7d2..6724f5a 100644
--- a/src/util.h
+++ b/src/util.h
@@ -119,6 +119,10 @@
 }
 #endif
 
-
+#if !defined(PY_SSIZE_T_MIN)
+typedef int Py_ssize_t;
+#define PY_SSIZE_T_MAX INT_MAX
+#define PY_SSIZE_T_MIN INT_MIN
+#endif
 
 #endif
diff --git a/test/test_ssl.py b/test/test_ssl.py
index 5d386a9..c460741 100644
--- a/test/test_ssl.py
+++ b/test/test_ssl.py
@@ -194,6 +194,7 @@
         cert = clientSSL.get_peer_certificate()
         self.assertEqual(cert.get_subject().CN, 'Testing Root CA')
 
+
     def test_load_verify_file(self):
         """
         L{Context.load_verify_locations} accepts a file name and uses the
@@ -255,7 +256,7 @@
             context = Context(SSLv3_METHOD)
             context.set_default_verify_paths()
             context.set_verify(
-                VERIFY_PEER, 
+                VERIFY_PEER,
                 lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
 
             client = socket()
@@ -277,6 +278,28 @@
         self.assertRaises(TypeError, context.set_default_verify_paths, 1)
         self.assertRaises(TypeError, context.set_default_verify_paths, "")
 
+    def test_add_extra_chain_cert_invalid_cert(self):
+        """
+        L{Context.add_extra_chain_cert} raises L{TypeError} if called with
+        other than one argument or if called with an object which is not an
+        instance of L{X509}.
+        """
+        context = Context(TLSv1_METHOD)
+        self.assertRaises(TypeError, context.add_extra_chain_cert)
+        self.assertRaises(TypeError, context.add_extra_chain_cert, object())
+        self.assertRaises(TypeError, context.add_extra_chain_cert, object(), object())
+
+
+    def test_add_extra_chain_cert(self):
+        """
+        L{Context.add_extra_chain_cert} accepts an L{X509} instance to add to
+        the certificate chain.
+        """
+        context = Context(TLSv1_METHOD)
+        context.add_extra_chain_cert(load_certificate(FILETYPE_PEM, cleartextCertificatePEM))
+        # XXX Oh no, actually asserting something about its behavior would be really hard.
+        # See #477521.
+
 
 
 class ConnectionTests(TestCase):
@@ -511,8 +534,8 @@
             established = True  # assume the best
             for ssl in client_conn, server_conn:
                 try:
-                    # Generally a recv() or send() could also work instead 
-                    # of do_handshake(), and we would stop on the first 
+                    # Generally a recv() or send() could also work instead
+                    # of do_handshake(), and we would stop on the first
                     # non-exception.
                     ssl.do_handshake()
                 except WantReadError:
@@ -583,6 +606,218 @@
         self.assertEquals(e.__class__, Error)
 
 
+    def _check_client_ca_list(self, func):
+        """
+        Verify the return value of the C{get_client_ca_list} method for server and client connections.
+
+        @param func: A function which will be called with the server context
+            before the client and server are connected to each other.  This
+            function should specify a list of CAs for the server to send to the
+            client and return that same list.  The list will be used to verify
+            that C{get_client_ca_list} returns the proper value at various
+            times.
+        """
+        server = self._server(None)
+        client = self._client(None)
+        self.assertEqual(client.get_client_ca_list(), [])
+        self.assertEqual(server.get_client_ca_list(), [])
+        ctx = server.get_context()
+        expected = func(ctx)
+        self.assertEqual(client.get_client_ca_list(), [])
+        self.assertEqual(server.get_client_ca_list(), expected)
+        self._loopback(client, server)
+        self.assertEqual(client.get_client_ca_list(), expected)
+        self.assertEqual(server.get_client_ca_list(), expected)
+
+
+    def test_set_client_ca_list_errors(self):
+        """
+        L{Context.set_client_ca_list} raises a L{TypeError} if called with a
+        non-list or a list that contains objects other than X509Names.
+        """
+        ctx = Context(TLSv1_METHOD)
+        self.assertRaises(TypeError, ctx.set_client_ca_list, "spam")
+        self.assertRaises(TypeError, ctx.set_client_ca_list, ["spam"])
+        self.assertIdentical(ctx.set_client_ca_list([]), None)
+
+
+    def test_set_empty_ca_list(self):
+        """
+        If passed an empty list, L{Context.set_client_ca_list} configures the
+        context to send no CA names to the client and, on both the server and
+        client sides, L{Connection.get_client_ca_list} returns an empty list
+        after the connection is set up.
+        """
+        def no_ca(ctx):
+            ctx.set_client_ca_list([])
+            return []
+        self._check_client_ca_list(no_ca)
+
+
+    def test_set_one_ca_list(self):
+        """
+        If passed a list containing a single X509Name,
+        L{Context.set_client_ca_list} configures the context to send that CA
+        name to the client and, on both the server and client sides,
+        L{Connection.get_client_ca_list} returns a list containing that
+        X509Name after the connection is set up.
+        """
+        cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
+        cadesc = cacert.get_subject()
+        def single_ca(ctx):
+            ctx.set_client_ca_list([cadesc])
+            return [cadesc]
+        self._check_client_ca_list(single_ca)
+
+
+    def test_set_multiple_ca_list(self):
+        """
+        If passed a list containing multiple X509Name objects,
+        L{Context.set_client_ca_list} configures the context to send those CA
+        names to the client and, on both the server and client sides,
+        L{Connection.get_client_ca_list} returns a list containing those
+        X509Names after the connection is set up.
+        """
+        secert = load_certificate(FILETYPE_PEM, server_cert_pem)
+        clcert = load_certificate(FILETYPE_PEM, server_cert_pem)
+
+        sedesc = secert.get_subject()
+        cldesc = clcert.get_subject()
+
+        def multiple_ca(ctx):
+            L = [sedesc, cldesc]
+            ctx.set_client_ca_list(L)
+            return L
+        self._check_client_ca_list(multiple_ca)
+
+
+    def test_reset_ca_list(self):
+        """
+        If called multiple times, only the X509Names passed to the final call
+        of L{Context.set_client_ca_list} are used to configure the CA names
+        sent to the client.
+        """
+        cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
+        secert = load_certificate(FILETYPE_PEM, server_cert_pem)
+        clcert = load_certificate(FILETYPE_PEM, server_cert_pem)
+
+        cadesc = cacert.get_subject()
+        sedesc = secert.get_subject()
+        cldesc = clcert.get_subject()
+
+        def changed_ca(ctx):
+            ctx.set_client_ca_list([sedesc, cldesc])
+            ctx.set_client_ca_list([cadesc])
+            return [cadesc]
+        self._check_client_ca_list(changed_ca)
+
+
+    def test_mutated_ca_list(self):
+        """
+        If the list passed to L{Context.set_client_ca_list} is mutated
+        afterwards, this does not affect the list of CA names sent to the
+        client.
+        """
+        cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
+        secert = load_certificate(FILETYPE_PEM, server_cert_pem)
+
+        cadesc = cacert.get_subject()
+        sedesc = secert.get_subject()
+
+        def mutated_ca(ctx):
+            L = [cadesc]
+            ctx.set_client_ca_list([cadesc])
+            L.append(sedesc)
+            return [cadesc]
+        self._check_client_ca_list(mutated_ca)
+
+
+    def test_add_client_ca_errors(self):
+        """
+        L{Context.add_client_ca} raises L{TypeError} if called with a non-X509
+        object or with a number of arguments other than one.
+        """
+        ctx = Context(TLSv1_METHOD)
+        cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
+        self.assertRaises(TypeError, ctx.add_client_ca)
+        self.assertRaises(TypeError, ctx.add_client_ca, "spam")
+        self.assertRaises(TypeError, ctx.add_client_ca, cacert, cacert)
+
+
+    def test_one_add_client_ca(self):
+        """
+        A certificate's subject can be added as a CA to be sent to the client
+        with L{Context.add_client_ca}.
+        """
+        cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
+        cadesc = cacert.get_subject()
+        def single_ca(ctx):
+            ctx.add_client_ca(cacert)
+            return [cadesc]
+        self._check_client_ca_list(single_ca)
+
+
+    def test_multiple_add_client_ca(self):
+        """
+        Multiple CA names can be sent to the client by calling
+        L{Context.add_client_ca} with multiple X509 objects.
+        """
+        cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
+        secert = load_certificate(FILETYPE_PEM, server_cert_pem)
+
+        cadesc = cacert.get_subject()
+        sedesc = secert.get_subject()
+
+        def multiple_ca(ctx):
+            ctx.add_client_ca(cacert)
+            ctx.add_client_ca(secert)
+            return [cadesc, sedesc]
+        self._check_client_ca_list(multiple_ca)
+
+
+    def test_set_and_add_client_ca(self):
+        """
+        A call to L{Context.set_client_ca_list} followed by a call to
+        L{Context.add_client_ca} results in using the CA names from the first
+        call and the CA name from the second call.
+        """
+        cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
+        secert = load_certificate(FILETYPE_PEM, server_cert_pem)
+        clcert = load_certificate(FILETYPE_PEM, server_cert_pem)
+
+        cadesc = cacert.get_subject()
+        sedesc = secert.get_subject()
+        cldesc = clcert.get_subject()
+
+        def mixed_set_add_ca(ctx):
+            ctx.set_client_ca_list([cadesc, sedesc])
+            ctx.add_client_ca(clcert)
+            return [cadesc, sedesc, cldesc]
+        self._check_client_ca_list(mixed_set_add_ca)
+
+
+    def test_set_after_add_client_ca(self):
+        """
+        A call to L{Context.set_client_ca_list} after a call to
+        L{Context.add_client_ca} replaces the CA name specified by the former
+        call with the names specified by the latter cal.
+        """
+        cacert = load_certificate(FILETYPE_PEM, root_cert_pem)
+        secert = load_certificate(FILETYPE_PEM, server_cert_pem)
+        clcert = load_certificate(FILETYPE_PEM, server_cert_pem)
+
+        cadesc = cacert.get_subject()
+        sedesc = secert.get_subject()
+        cldesc = clcert.get_subject()
+
+        def set_replaces_add_ca(ctx):
+            ctx.add_client_ca(clcert)
+            ctx.set_client_ca_list([cadesc])
+            ctx.add_client_ca(secert)
+            return [cadesc, sedesc]
+        self._check_client_ca_list(set_replaces_add_ca)
+
+
 
 if __name__ == '__main__':
     main()