summaryrefslogtreecommitdiff
path: root/OpenSSL
diff options
context:
space:
mode:
authorJean-Paul Calderone <exarkun@divmod.com>2011-05-17 15:45:21 -0400
committerJean-Paul Calderone <exarkun@divmod.com>2011-05-17 15:45:21 -0400
commit95b92c7888b4acce21e87ec975cac31661469e8a (patch)
treea264dc0f39919ecaaa151fce272eeee689f8d541 /OpenSSL
parent9eff5699339c34439d7085e937abd0f3b9235afe (diff)
downloadpyopenssl-95b92c7888b4acce21e87ec975cac31661469e8a.tar.gz
Apply the get_peer_cert_chain parts of okuda's patch
Diffstat (limited to 'OpenSSL')
-rwxr-xr-xOpenSSL/ssl/connection.c38
-rw-r--r--OpenSSL/test/test_ssl.py31
-rw-r--r--OpenSSL/tsafe.py2
3 files changed, 70 insertions, 1 deletions
diff --git a/OpenSSL/ssl/connection.c b/OpenSSL/ssl/connection.c
index 5b304b1..09e2607 100755
--- a/OpenSSL/ssl/connection.c
+++ b/OpenSSL/ssl/connection.c
@@ -1098,6 +1098,43 @@ ssl_Connection_get_peer_certificate(ssl_ConnectionObj *self, PyObject *args)
}
}
+static char ssl_Connection_get_peer_cert_chain_doc[] = "\n\
+Retrieve the other side's certificate (if any)\n\
+\n\
+Arguments: self - The Connection object\n\
+ args - The Python argument tuple, should be empty\n\
+Returns: The peer's certificates chain tuple\n\
+";
+static PyObject *
+ssl_Connection_get_peer_cert_chain(ssl_ConnectionObj *self, PyObject *args)
+{
+ STACK_OF(X509) *sk;
+ PyObject *tpl, *item;
+ Py_ssize_t i;
+
+ if (!PyArg_ParseTuple(args, ":get_peer_cert_chain"))
+ return NULL;
+
+ sk = SSL_get_peer_cert_chain(self->ssl);
+ if (sk != NULL)
+ {
+ tpl = PyTuple_New(sk_X509_num(sk));
+ for (i=0; i<sk_X509_num(sk); i++)
+ {
+ item = (PyObject *)crypto_X509_New(sk_X509_value(sk,i), 1);
+ Py_INCREF(item);
+ PyTuple_SET_ITEM(tpl, i, item);
+ }
+ return tpl;
+ }
+ else
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+}
+
static char ssl_Connection_want_read_doc[] = "\n\
Checks if more data has to be read from the transport layer to complete an\n\
operation.\n\
@@ -1175,6 +1212,7 @@ static PyMethodDef ssl_Connection_methods[] =
ADD_METHOD(master_key),
ADD_METHOD(sock_shutdown),
ADD_METHOD(get_peer_certificate),
+ ADD_METHOD(get_peer_cert_chain),
ADD_METHOD(want_read),
ADD_METHOD(want_write),
ADD_METHOD(set_accept_state),
diff --git a/OpenSSL/test/test_ssl.py b/OpenSSL/test/test_ssl.py
index ff2e725..5752d13 100644
--- a/OpenSSL/test/test_ssl.py
+++ b/OpenSSL/test/test_ssl.py
@@ -307,6 +307,37 @@ class ContextTests(TestCase, _LoopbackMixin):
context = Context(TLSv1_METHOD)
self.assertRaises(TypeError, context.get_timeout, None)
+ def test_get_peer_cert_chain(self):
+ """
+ L{Connection.get_peer_cert_chain} returns the tuple of certificates
+ which the connected server returned for the certification verification.
+ """
+ # Testing this requires a server with a certificate signed by one of
+ # the CAs in the platform CA location. Getting one of those costs
+ # money. Fortunately (or unfortunately, depending on your
+ # perspective), it's easy to think of a public server on the
+ # internet which has such a certificate. Connecting to the network
+ # in a unit test is bad, but it's the only way I can think of to
+ # really test this. -exarkun
+
+ # Arg, verisign.com doesn't speak TLSv1
+ context = Context(SSLv3_METHOD)
+
+ client = socket()
+ client.connect(('verisign.com', 443))
+ clientSSL = Connection(context, client)
+ clientSSL.set_connect_state()
+ clientSSL.do_handshake()
+ cert = clientSSL.get_peer_certificate()
+ certs = clientSSL.get_peer_cert_chain()
+ self.assertEqual(dump_certificate(FILETYPE_PEM, cert),
+ dump_certificate(FILETYPE_PEM, certs[0]))
+ self.assertEqual(certs[0].get_subject().CN, 'www.verisign.com')
+ self.assertEqual(certs[1].get_subject().CN,
+ 'VeriSign Class 3 Extended Validation SSL SGC CA')
+ self.assertEqual(certs[2].get_subject().CN,
+ 'VeriSign Class 3 Public Primary Certification Authority - G5')
+
def test_timeout(self):
"""
diff --git a/OpenSSL/tsafe.py b/OpenSSL/tsafe.py
index fe4b75f..9d7ad2f 100644
--- a/OpenSSL/tsafe.py
+++ b/OpenSSL/tsafe.py
@@ -16,7 +16,7 @@ class Connection:
'setblocking', 'fileno', 'shutdown', 'close', 'get_cipher_list',
'getpeername', 'getsockname', 'getsockopt', 'setsockopt',
'makefile', 'get_app_data', 'set_app_data', 'state_string',
- 'sock_shutdown', 'get_peer_certificate', 'want_read',
+ 'sock_shutdown', 'get_peer_certificate', 'get_peer_cert_chain', 'want_read',
'want_write', 'set_connect_state', 'set_accept_state',
'connect_ex', 'sendall'):
exec("""def %s(self, *args):