mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Issue #18143: Implement ssl.get_default_verify_paths() in order to debug
the default locations for cafile and capath.
This commit is contained in:
parent
302b8c31ec
commit
6d7ad13a45
5 changed files with 97 additions and 1 deletions
|
@ -343,6 +343,23 @@ Certificate handling
|
||||||
Given a certificate as an ASCII PEM string, returns a DER-encoded sequence of
|
Given a certificate as an ASCII PEM string, returns a DER-encoded sequence of
|
||||||
bytes for that same certificate.
|
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
|
Constants
|
||||||
^^^^^^^^^
|
^^^^^^^^^
|
||||||
|
|
||||||
|
@ -787,7 +804,8 @@ to speed up repeated connections from the same clients.
|
||||||
other peers' certificates when :data:`verify_mode` is other than
|
other peers' certificates when :data:`verify_mode` is other than
|
||||||
:data:`CERT_NONE`. At least one of *cafile* or *capath* must be specified.
|
: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
|
CA certificates in PEM format. See the discussion of
|
||||||
:ref:`ssl-certificates` for more information about how to arrange the
|
:ref:`ssl-certificates` for more information about how to arrange the
|
||||||
certificates in this file.
|
certificates in this file.
|
||||||
|
|
20
Lib/ssl.py
20
Lib/ssl.py
|
@ -89,6 +89,8 @@ ALERT_DESCRIPTION_UNKNOWN_PSK_IDENTITY
|
||||||
|
|
||||||
import textwrap
|
import textwrap
|
||||||
import re
|
import re
|
||||||
|
import os
|
||||||
|
import collections
|
||||||
|
|
||||||
import _ssl # if we can't import it, let the error propagate
|
import _ssl # if we can't import it, let the error propagate
|
||||||
|
|
||||||
|
@ -222,6 +224,24 @@ def match_hostname(cert, hostname):
|
||||||
"subjectAltName fields were found")
|
"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):
|
class SSLContext(_SSLContext):
|
||||||
"""An SSLContext holds various SSL-related configuration options and
|
"""An SSLContext holds various SSL-related configuration options and
|
||||||
data, such as certificates and possibly a private key."""
|
data, such as certificates and possibly a private key."""
|
||||||
|
|
|
@ -394,6 +394,19 @@ class BasicSocketTests(unittest.TestCase):
|
||||||
support.gc_collect()
|
support.gc_collect()
|
||||||
self.assertIn(r, str(cm.warning.args[0]))
|
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):
|
class ContextTests(unittest.TestCase):
|
||||||
|
|
||||||
@skip_if_broken_ubuntu_ssl
|
@skip_if_broken_ubuntu_ssl
|
||||||
|
|
|
@ -115,6 +115,9 @@ Core and Builtins
|
||||||
Library
|
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 #17314: Move multiprocessing.forking over to importlib.
|
||||||
|
|
||||||
- Issue #11959: SMTPServer and SMTPChannel now take an optional map, use of
|
- Issue #11959: SMTPServer and SMTPChannel now take an optional map, use of
|
||||||
|
|
|
@ -2761,6 +2761,46 @@ fails or if it does provide enough data to seed PRNG.");
|
||||||
|
|
||||||
#endif
|
#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. */
|
/* List of functions exported by this module. */
|
||||||
|
@ -2779,6 +2819,8 @@ static PyMethodDef PySSL_methods[] = {
|
||||||
PySSL_RAND_egd_doc},
|
PySSL_RAND_egd_doc},
|
||||||
{"RAND_status", (PyCFunction)PySSL_RAND_status, METH_NOARGS,
|
{"RAND_status", (PyCFunction)PySSL_RAND_status, METH_NOARGS,
|
||||||
PySSL_RAND_status_doc},
|
PySSL_RAND_status_doc},
|
||||||
|
{"get_default_verify_paths", (PyCFunction)get_default_verify_paths,
|
||||||
|
METH_NOARGS, PySSL_get_default_verify_paths_doc},
|
||||||
#endif
|
#endif
|
||||||
{NULL, NULL} /* Sentinel */
|
{NULL, NULL} /* Sentinel */
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue