1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
# Truststore
```{toctree}
:maxdepth: 2
:caption: Contents
```
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](https://pypi.org/project/truststore) with pip:
```{code-block} shell
$ python -m pip install truststore
```
Truststore **requires Python 3.10 or later** and supports the following platforms:
- macOS 10.8+ via [Security framework](https://developer.apple.com/documentation/security)
- Windows via [CryptoAPI](https://docs.microsoft.com/en-us/windows/win32/seccrypto/cryptography-functions#certificate-verification-functions)
- 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.
```python
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`:
```python
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:
```python
# 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](https://discuss.python.org/t/announcement-pip-22-2-release/17543) 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:
```{code-block} bash
# 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](https://pip.pypa.io/en/stable/user_guide/#using-system-trust-stores-for-verifying-https).
### Using truststore with urllib3
```{code-block} python
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:
```{code-block} python
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 {py:class}`socket.socket` or {py:class}`ssl.MemoryBIO` which means both synchronous and asynchronous I/O can be used:
```{code-block} python
import aiohttp
import truststore
truststore.inject_into_ssl()
async with aiohttp.ClientSession() as http_client:
async with http_client.get("https://example.com") as http_response:
...
```
If you'd like to use the `truststore.SSLContext` directly you can pass
the instance via the `ssl` parameter:
```{code-block} python
import ssl
import aiohttp
import truststore
ctx = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
async with aiohttp.ClientSession(ssl=ctx) as http_client:
async with http_client.get("https://example.com") as http_response:
...
```
### Using truststore with Requests
Just like with `urllib3` using `truststore.inject_into_ssl()` is the easiest method for using Truststore with Requests:
```{code-block} python
import requests
import truststore
truststore.inject_into_ssl()
resp = requests.request("GET", "https://example.com")
```
## Prior art
* [pip v22.2 with support for `--use-feature=truststore`](https://discuss.python.org/t/announcement-pip-22-2-release/17543)
* [The future of trust stores in Python (PyCon US 2022 lightning talk)](https://youtu.be/1IiL31tUEVk?t=698) ([slides](https://speakerdeck.com/sethmlarson/the-future-of-trust-stores-in-python))
* [Experimental APIs in Python 3.10 and the future of trust stores](https://sethmlarson.dev/blog/2021-11-27/experimental-python-3.10-apis-and-trust-stores)
* [PEP 543: A Unified TLS API for Python](https://www.python.org/dev/peps/pep-0543)
## License
MIT
|