support capath parameter to load_verify_locations; add wrapper for set_default_verify_paths
diff --git a/src/ssl/context.c b/src/ssl/context.c
index 6497304..88809a0 100644
--- a/src/ssl/context.c
+++ b/src/ssl/context.c
@@ -241,18 +241,20 @@
\n\
Arguments: self - The Context object\n\
args - The Python argument tuple, should be:\n\
- cafile - Which file we can find the certificates\n\
+ cafile - In which file we can find the certificates\n\
+ capath - In which directory we can find the certificates\r\
Returns: None\n\
";
static PyObject *
-ssl_Context_load_verify_locations(ssl_ContextObj *self, PyObject *args)
-{
- char *cafile;
+ssl_Context_load_verify_locations(ssl_ContextObj *self, PyObject *args) {
+ char *cafile = NULL;
+ char *capath = NULL;
- if (!PyArg_ParseTuple(args, "s:load_verify_locations", &cafile))
+ if (!PyArg_ParseTuple(args, "z|z:load_verify_locations", &cafile, &capath)) {
return NULL;
+ }
- if (!SSL_CTX_load_verify_locations(self->ctx, cafile, NULL))
+ if (!SSL_CTX_load_verify_locations(self->ctx, cafile, capath))
{
exception_from_error_queue();
return NULL;
@@ -264,6 +266,22 @@
}
}
+static char ssl_Context_set_default_verify_paths_doc[] = "\n\
+Use the platform-specific CA certificate locations\n\
+\n\
+Arguments: self - The Context object\n\
+ args - None\n\
+\n\
+Returns: None\n\
+";
+static PyObject *
+ssl_Context_set_default_verify_paths(ssl_ContextObj *self, PyObject *args) {
+ SSL_CTX_set_default_verify_paths(self->ctx);
+ Py_INCREF(Py_None);
+ return Py_None;
+};
+
+
static char ssl_Context_set_passwd_cb_doc[] = "\n\
Set the passphrase callback\n\
\n\
@@ -955,6 +973,7 @@
static PyMethodDef ssl_Context_methods[] = {
ADD_METHOD(load_verify_locations),
ADD_METHOD(set_passwd_cb),
+ ADD_METHOD(set_default_verify_paths),
ADD_METHOD(use_certificate_chain_file),
ADD_METHOD(use_certificate_file),
ADD_METHOD(use_certificate),
diff --git a/test/test_ssl.py b/test/test_ssl.py
index 1028c0c..dd42a10 100644
--- a/test/test_ssl.py
+++ b/test/test_ssl.py
@@ -7,6 +7,8 @@
from unittest import TestCase
from tempfile import mktemp
from socket import socket
+from os import makedirs, symlink
+from os.path import join
from OpenSSL.crypto import TYPE_RSA, FILETYPE_PEM, PKey, dump_privatekey, load_certificate, load_privatekey
from OpenSSL.SSL import WantReadError, Context, Connection, Error
@@ -117,11 +119,7 @@
self.assertTrue(called)
- def test_load_verify_file(self):
- """
- L{Context.load_verify_locations} accepts a file name and uses the
- certificates within for verification purposes.
- """
+ def _load_verify_locations_test(self, *args):
port = socket()
port.bind(('', 0))
port.listen(1)
@@ -130,13 +128,8 @@
client.setblocking(False)
client.connect_ex(port.getsockname())
- cafile = self.mktemp()
- fObj = file(cafile, 'w')
- fObj.write(cleartextCertificatePEM)
- fObj.close()
-
clientContext = Context(TLSv1_METHOD)
- clientContext.load_verify_locations(cafile)
+ clientContext.load_verify_locations(*args)
# Require that the server certificate verify properly or the
# connection will fail.
clientContext.set_verify(
@@ -172,6 +165,18 @@
cert = clientSSL.get_peer_certificate()
self.assertEqual(cert.get_subject().CN, 'pyopenssl.sf.net')
+ def test_load_verify_file(self):
+ """
+ L{Context.load_verify_locations} accepts a file name and uses the
+ certificates within for verification purposes.
+ """
+ cafile = self.mktemp()
+ fObj = file(cafile, 'w')
+ fObj.write(cleartextCertificatePEM)
+ fObj.close()
+
+ self._load_verify_locations_test(cafile)
+
def test_load_verify_invalid_file(self):
"""
@@ -181,3 +186,51 @@
clientContext = Context(TLSv1_METHOD)
self.assertRaises(
Error, clientContext.load_verify_locations, self.mktemp())
+
+
+ def test_load_verify_directory(self):
+ """
+ L{Context.load_verify_locations} accepts a directory name and uses
+ the certificates within for verification purposes.
+ """
+ capath = self.mktemp()
+ makedirs(capath)
+ cafile = join(capath, 'cert.pem')
+ fObj = file(cafile, 'w')
+ fObj.write(cleartextCertificatePEM)
+ fObj.close()
+
+ # Hash value computed manually with c_rehash to avoid depending on
+ # c_rehash in the test suite.
+ symlink('cert.pem', join(capath, '07497d9e.0'))
+
+ self._load_verify_locations_test(None, capath)
+
+
+ def test_set_default_verify_paths(self):
+ """
+ L{Context.set_default_verify_paths} causes the platform-specific CA
+ certificate locations to be used for verification purposes.
+ """
+ # 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)
+ context.set_default_verify_paths()
+ context.set_verify(
+ VERIFY_PEER,
+ lambda conn, cert, errno, depth, preverify_ok: preverify_ok)
+
+ client = socket()
+ client.connect(('verisign.com', 443))
+ clientSSL = Connection(context, client)
+ clientSSL.set_connect_state()
+ clientSSL.do_handshake()
+ clientSSL.send('GET / HTTP/1.0\r\n\r\n')
+ self.assertTrue(clientSSL.recv(1024))