Truststore¶
Truststore is a library which exposes native system certificate stores (ie “trust stores”)
through an ssl.SSLContext
-like API. This means that Python applications no longer need to
rely on certifi as a root certificate store. Native system certificate stores
have many helpful features compared to a static certificate bundle like certifi:
Automatically update certificates as new CAs are created and removed
Fetch missing intermediate certificates
Check certificates against certificate revocation lists (CRLs) to avoid monster-in-the-middle (MITM) attacks
Managed per-system rather than per-application by a operations/IT team
PyPI is no longer a CA distribution channel 🥳
Right now truststore is a stand-alone library that can be installed globally in your application to immediately take advantage of the benefits in Python 3.10+. Truststore has also been integrated into pip as an opt-in method for verifying HTTPS certificates with truststore instead of certifi.
Long-term the hope is to make truststore the default way to verify HTTPS certificates in pip and to add this functionality into Python itself. Wish us luck!
Installation¶
Truststore can be installed from PyPI with pip:
$ python -m pip install truststore
Truststore requires Python 3.10 or later and supports the following platforms:
macOS 10.8+ via Security framework
Windows via CryptoAPI
Linux via OpenSSL
User Guide¶
Warning
PLEASE READ: inject_into_ssl()
must not be used by libraries or packages as it will cause issues on import time when integrated with other libraries.
Libraries and packages should instead use truststore.SSLContext
directly which is detailed below.
The inject_into_ssl()
function is intended only for use in applications and scripts.
You can inject truststore
into the standard library ssl
module so the functionality is used
by every library by default. To do so use the truststore.inject_into_ssl()
function.
The call to truststore.inject_into_ssl()
should be called as early as possible in
your program as modules that have already imported ssl.SSLContext
won’t be affected.
import truststore
truststore.inject_into_ssl()
# Automatically works with urllib3, requests, aiohttp, and more:
import urllib3
http = urllib3.PoolManager()
resp = http.request("GET", "https://example.com")
import aiohttp
http = aiohttp.ClientSession()
resp = await http.request("GET", "https://example.com")
import requests
resp = requests.get("https://example.com")
If you’d like finer-grained control you can create your own truststore.SSLContext
instance
and use it anywhere you’d use an ssl.SSLContext
:
import ssl
import truststore
ctx = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
import urllib3
http = urllib3.PoolManager(ssl_context=ctx)
resp = http.request("GET", "https://example.com")
If Truststore can’t work for a given platform due to APIs not being available then
at import time the exception ImportError
will be raised with an informative message:
# On Python 3.9 and earlier:
import truststore # Raises 'ImportError'
# On macOS 10.7 and earlier:
import truststore # Raises 'ImportError'
Using truststore with pip¶
Pip v22.2 includes experimental support for verifying certificates with system trust stores using truststore
. To enable the feature, use the flag --use-feature=truststore
when installing a package like so:
# Install Django using system trust stores
$ python -m pip install --use-feature=truststore Django
This requires truststore
to be installed in the same environment as the one running pip and to be running Python 3.10 or later. For more information you can read the pip documentation about the feature.
Using truststore with urllib3¶
import urllib3
import truststore
truststore.inject_into_ssl()
http = urllib3.PoolManager()
resp = http.request("GET", "https://example.com")
If you’d like to use the truststore.SSLContext
directly you can pass
the instance via the ssl_context
parameter:
import ssl
import urllib3
import truststore
ctx = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
http = urllib3.PoolManager(ssl_context=ctx)
resp = http.request("GET", "https://example.com")
Using truststore with aiohttp¶
Truststore supports wrapping either socket.socket
or ssl.MemoryBIO
which means both synchronous and asynchronous I/O can be used:
import aiohttp
import truststore
truststore.inject_into_ssl()
http = aiohttp.ClientSession()
resp = await http.request("GET", "https://example.com")
If you’d like to use the truststore.SSLContext
directly you can pass
the instance via the ssl
parameter:
import ssl
import aiohttp
import truststore
ctx = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
http = aiohttp.ClientSession(ssl=ctx)
resp = await http.request("GET", "https://example.com")
Using truststore with Requests¶
Just like with urllib3
using truststore.inject_into_ssl()
is the easiest method for using Truststore with Requests:
import requests
import truststore
truststore.inject_into_ssl()
resp = requests.request("GET", "https://example.com")
Prior art¶
License¶
MIT