[Python-checkins] cpython: Issue #18143: Implement ssl.get_default_verify_paths() in order to debug

christian.heimes python-checkins at python.org
Sun Jun 9 18:03:10 CEST 2013


http://hg.python.org/cpython/rev/a4d31e56075d
changeset:   84068:a4d31e56075d
user:        Christian Heimes <christian at cheimes.de>
date:        Sun Jun 09 18:02:55 2013 +0200
summary:
  Issue #18143: Implement ssl.get_default_verify_paths() in order to debug
the default locations for cafile and capath.

files:
  Doc/library/ssl.rst  |  20 ++++++++++++++-
  Lib/ssl.py           |  20 +++++++++++++++
  Lib/test/test_ssl.py |  13 +++++++++
  Misc/NEWS            |   3 ++
  Modules/_ssl.c       |  42 ++++++++++++++++++++++++++++++++
  5 files changed, 97 insertions(+), 1 deletions(-)


diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -343,6 +343,23 @@
    Given a certificate as an ASCII PEM string, returns a DER-encoded sequence of
    bytes for that same certificate.
 
+.. function:: get_default_verify_paths()
+
+   Returns a named tuple with paths to OpenSSL's default cafile and capath.
+   The paths are the same as used by
+   :meth:`SSLContext.set_default_verify_paths`. The return value is a
+   :term:`named tuple` ``DefaultVerifyPaths``:
+
+   * :attr:`cafile` - resolved path to cafile or None if the file doesn't exist,
+   * :attr:`capath` - resolved path to capath or None if the directory doesn't exist,
+   * :attr:`openssl_cafile_env` - OpenSSL's environment key that points to a cafile,
+   * :attr:`openssl_cafile` - hard coded path to a cafile,
+   * :attr:`openssl_capath_env` - OpenSSL's environment key that points to a capath,
+   * :attr:`openssl_capath` - hard coded path to a capath directory
+
+   .. versionadded:: 3.4
+
+
 Constants
 ^^^^^^^^^
 
@@ -787,7 +804,8 @@
    other peers' certificates when :data:`verify_mode` is other than
    :data:`CERT_NONE`.  At least one of *cafile* or *capath* must be specified.
 
-   The *cafile* string, if present, is the path to a file of concatenated
+   The *cafile* string, if present, is the p
+   ath to a file of concatenated
    CA certificates in PEM format. See the discussion of
    :ref:`ssl-certificates` for more information about how to arrange the
    certificates in this file.
diff --git a/Lib/ssl.py b/Lib/ssl.py
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -89,6 +89,8 @@
 
 import textwrap
 import re
+import os
+import collections
 
 import _ssl             # if we can't import it, let the error propagate
 
@@ -222,6 +224,24 @@
             "subjectAltName fields were found")
 
 
+DefaultVerifyPaths = collections.namedtuple("DefaultVerifyPaths",
+    "cafile capath openssl_cafile_env openssl_cafile openssl_capath_env "
+    "openssl_capath")
+
+def get_default_verify_paths():
+    """Return paths to default cafile and capath.
+    """
+    parts = _ssl.get_default_verify_paths()
+
+    # environment vars shadow paths
+    cafile = os.environ.get(parts[0], parts[1])
+    capath = os.environ.get(parts[2], parts[3])
+
+    return DefaultVerifyPaths(cafile if os.path.isfile(cafile) else None,
+                              capath if os.path.isdir(capath) else None,
+                              *parts)
+
+
 class SSLContext(_SSLContext):
     """An SSLContext holds various SSL-related configuration options and
     data, such as certificates and possibly a private key."""
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -394,6 +394,19 @@
             support.gc_collect()
         self.assertIn(r, str(cm.warning.args[0]))
 
+    def test_get_default_verify_paths(self):
+        paths = ssl.get_default_verify_paths()
+        self.assertEqual(len(paths), 6)
+        self.assertIsInstance(paths, ssl.DefaultVerifyPaths)
+
+        with support.EnvironmentVarGuard() as env:
+            env["SSL_CERT_DIR"] = CAPATH
+            env["SSL_CERT_FILE"] = CERTFILE
+            paths = ssl.get_default_verify_paths()
+            self.assertEqual(paths.cafile, CERTFILE)
+            self.assertEqual(paths.capath, CAPATH)
+
+
 class ContextTests(unittest.TestCase):
 
     @skip_if_broken_ubuntu_ssl
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -115,6 +115,9 @@
 Library
 -------
 
+- Issue #18143: Implement ssl.get_default_verify_paths() in order to debug
+  the default locations for cafile and capath.
+
 - Issue #17314: Move multiprocessing.forking over to importlib.
 
 - Issue #11959: SMTPServer and SMTPChannel now take an optional map, use of
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -2761,6 +2761,46 @@
 
 #endif
 
+PyDoc_STRVAR(PySSL_get_default_verify_paths_doc,
+"get_default_verify_paths() -> tuple\n\
+\n\
+Return search paths and environment vars that are used by SSLContext's\n\
+set_default_verify_paths() to load default CAs. The values are\n\
+'cert_file_env', 'cert_file', 'cert_dir_env', 'cert_dir'.");
+
+static PyObject *
+get_default_verify_paths(PyObject *self)
+{
+    PyObject *ofile_env = NULL;
+    PyObject *ofile = NULL;
+    PyObject *odir_env = NULL;
+    PyObject *odir = NULL;
+
+#define convert(info, target) { \
+        const char *tmp = (info); \
+        target = NULL; \
+        if (!tmp) { Py_INCREF(Py_None); target = Py_None; } \
+        else if ((target = PyUnicode_DecodeFSDefault(tmp)) == NULL) { \
+            target = PyBytes_FromString(tmp); } \
+        if (!target) goto error; \
+    } while(0)
+
+    convert(X509_get_default_cert_file_env(), ofile_env);
+    convert(X509_get_default_cert_file(), ofile);
+    convert(X509_get_default_cert_dir_env(), odir_env);
+    convert(X509_get_default_cert_dir(), odir);
+#undef convert
+
+    return Py_BuildValue("(OOOO)", ofile_env, ofile, odir_env, odir);
+
+  error:
+    Py_XDECREF(ofile_env);
+    Py_XDECREF(ofile);
+    Py_XDECREF(odir_env);
+    Py_XDECREF(odir);
+    return NULL;
+}
+
 
 
 /* List of functions exported by this module. */
@@ -2779,6 +2819,8 @@
      PySSL_RAND_egd_doc},
     {"RAND_status",         (PyCFunction)PySSL_RAND_status, METH_NOARGS,
      PySSL_RAND_status_doc},
+    {"get_default_verify_paths", (PyCFunction)get_default_verify_paths,
+     METH_NOARGS, PySSL_get_default_verify_paths_doc},
 #endif
     {NULL,                  NULL}            /* Sentinel */
 };

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list