0
# Trust Store Management
1
2
Access and export operating system trust store certificates for use with OpenSSL-based code. Provides CA certificate bundles in PEM format, enabling applications to use OS-managed trust roots with custom TLS implementations.
3
4
```python
5
from oscrypto import trust_list
6
from oscrypto.errors import CACertsError
7
```
8
9
## Capabilities
10
11
### Trust List Access
12
13
Retrieve CA certificates from the operating system's trust store.
14
15
```python { .api }
16
def get_list() -> List[Certificate]:
17
"""
18
Get list of CA certificates from the OS trust store.
19
20
Returns:
21
List of Certificate objects representing trusted CA certificates
22
23
Raises:
24
CACertsError if unable to export certificates from OS trust store
25
"""
26
27
def get_path() -> str:
28
"""
29
Get path to a CA certificate bundle file in PEM format.
30
31
Returns:
32
String path to a temporary PEM file containing CA certificates
33
34
Note:
35
The returned file is cached and may be automatically cleaned up.
36
Copy the file if you need persistent access.
37
"""
38
39
def clear_cache() -> None:
40
"""
41
Clear cached CA certificate data and temporary files.
42
43
Note:
44
Forces regeneration of CA bundle on next access.
45
"""
46
```
47
48
## Usage Examples
49
50
### Basic Trust Store Access
51
52
```python
53
from oscrypto import trust_list
54
55
# Get CA certificates as Certificate objects
56
ca_certs = trust_list.get_list()
57
print(f"Found {len(ca_certs)} CA certificates in OS trust store")
58
59
# Examine a few certificates
60
for i, cert in enumerate(ca_certs[:3]):
61
print(f"CA {i+1}: {cert.subject}")
62
print(f" Issuer: {cert.issuer}")
63
print(f" Valid until: {cert.not_valid_after}")
64
print()
65
```
66
67
### PEM Bundle for OpenSSL
68
69
```python
70
from oscrypto import trust_list
71
import shutil
72
73
# Get path to PEM bundle file
74
pem_path = trust_list.get_path()
75
print(f"CA bundle available at: {pem_path}")
76
77
# Copy to persistent location
78
persistent_path = "/etc/ssl/oscrypto-ca-bundle.pem"
79
try:
80
shutil.copy2(pem_path, persistent_path)
81
print(f"CA bundle copied to: {persistent_path}")
82
except PermissionError:
83
print("Permission denied - run as administrator/root")
84
85
# Read PEM content
86
with open(pem_path, 'r') as f:
87
pem_data = f.read()
88
cert_count = pem_data.count('-----BEGIN CERTIFICATE-----')
89
print(f"PEM bundle contains {cert_count} certificates")
90
```
91
92
### OpenSSL Integration
93
94
```python
95
from oscrypto import trust_list
96
import ssl
97
import socket
98
99
# Get CA bundle path for use with Python's ssl module
100
ca_bundle_path = trust_list.get_path()
101
102
# Create SSL context with OS trust roots
103
context = ssl.create_default_context(cafile=ca_bundle_path)
104
105
# Use with HTTPS connections
106
with socket.create_connection(('www.example.com', 443)) as sock:
107
with context.wrap_socket(sock, server_hostname='www.example.com') as ssock:
108
print(f"SSL version: {ssock.version()}")
109
print(f"Cipher: {ssock.cipher()}")
110
111
# Send HTTP request
112
ssock.send(b'GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n')
113
response = ssock.recv(1024)
114
print(f"Response: {response[:100]}...")
115
```
116
117
### Certificate Analysis
118
119
```python
120
from oscrypto import trust_list
121
from collections import defaultdict
122
import datetime
123
124
def analyze_trust_store():
125
"""Analyze CA certificates in the trust store."""
126
ca_certs = trust_list.get_list()
127
128
# Group by issuer
129
issuers = defaultdict(int)
130
key_sizes = defaultdict(int)
131
expiring_soon = []
132
133
now = datetime.datetime.now()
134
one_year = datetime.timedelta(days=365)
135
136
for cert in ca_certs:
137
# Count by issuer
138
issuer_cn = cert.issuer.get('common_name', 'Unknown')
139
issuers[issuer_cn] += 1
140
141
# Analyze key sizes
142
if hasattr(cert.public_key, 'bit_size'):
143
key_sizes[cert.public_key.bit_size] += 1
144
145
# Check expiration
146
if cert.not_valid_after and cert.not_valid_after < now + one_year:
147
expiring_soon.append((cert.subject.get('common_name', 'Unknown'), cert.not_valid_after))
148
149
print(f"Trust Store Analysis ({len(ca_certs)} certificates)")
150
print("=" * 50)
151
152
print("Top 10 Certificate Issuers:")
153
for issuer, count in sorted(issuers.items(), key=lambda x: x[1], reverse=True)[:10]:
154
print(f" {issuer}: {count} certificates")
155
156
print("\nKey Size Distribution:")
157
for size, count in sorted(key_sizes.items()):
158
print(f" {size}-bit: {count} certificates")
159
160
if expiring_soon:
161
print(f"\nCertificates expiring within 1 year ({len(expiring_soon)}):")
162
for name, expiry in sorted(expiring_soon, key=lambda x: x[1])[:5]:
163
print(f" {name}: expires {expiry.strftime('%Y-%m-%d')}")
164
165
# Run analysis
166
analyze_trust_store()
167
```
168
169
### Custom Trust Root Management
170
171
```python
172
from oscrypto import trust_list, asymmetric
173
import tempfile
174
import os
175
176
def create_custom_ca_bundle(extra_certs_paths: list) -> str:
177
"""Create a custom CA bundle combining OS certs with additional ones."""
178
179
# Get OS CA certificates
180
os_ca_path = trust_list.get_path()
181
182
# Read OS CA bundle
183
with open(os_ca_path, 'r') as f:
184
ca_bundle_content = f.read()
185
186
# Add custom certificates
187
for cert_path in extra_certs_paths:
188
if os.path.exists(cert_path):
189
with open(cert_path, 'rb') as f:
190
cert_data = f.read()
191
192
# Load and validate certificate
193
try:
194
cert = asymmetric.load_certificate(cert_data)
195
print(f"Adding custom CA: {cert.subject}")
196
197
# Convert to PEM if needed
198
if cert_data.startswith(b'-----BEGIN'):
199
ca_bundle_content += "\n" + cert_data.decode('utf-8')
200
else:
201
# Convert DER to PEM
202
pem_cert = asymmetric.dump_certificate(cert)
203
pem_lines = [
204
"-----BEGIN CERTIFICATE-----",
205
pem_cert.b64encode().decode('ascii'),
206
"-----END CERTIFICATE-----"
207
]
208
ca_bundle_content += "\n" + "\n".join(pem_lines) + "\n"
209
210
except Exception as e:
211
print(f"Failed to load certificate {cert_path}: {e}")
212
213
# Write combined bundle to temporary file
214
with tempfile.NamedTemporaryFile(mode='w', suffix='.pem', delete=False) as f:
215
f.write(ca_bundle_content)
216
custom_bundle_path = f.name
217
218
print(f"Custom CA bundle created: {custom_bundle_path}")
219
return custom_bundle_path
220
221
# Example usage
222
custom_certs = [
223
'/path/to/internal-ca.pem',
224
'/path/to/test-ca.crt'
225
]
226
227
custom_bundle = create_custom_ca_bundle(custom_certs)
228
```
229
230
### Cache Management
231
232
```python
233
from oscrypto import trust_list
234
import time
235
import os
236
237
def demonstrate_caching():
238
"""Demonstrate trust store caching behavior."""
239
240
print("Initial trust store access...")
241
start_time = time.time()
242
ca_path1 = trust_list.get_path()
243
initial_time = time.time() - start_time
244
print(f"First access took {initial_time:.3f} seconds")
245
print(f"Bundle path: {ca_path1}")
246
print(f"Bundle size: {os.path.getsize(ca_path1)} bytes")
247
248
print("\nSecond access (cached)...")
249
start_time = time.time()
250
ca_path2 = trust_list.get_path()
251
cached_time = time.time() - start_time
252
print(f"Cached access took {cached_time:.3f} seconds")
253
print(f"Same path: {ca_path1 == ca_path2}")
254
255
print(f"\nCaching speedup: {initial_time / cached_time:.1f}x faster")
256
257
print("\nClearing cache...")
258
trust_list.clear_cache()
259
260
print("Post-clear access...")
261
start_time = time.time()
262
ca_path3 = trust_list.get_path()
263
refresh_time = time.time() - start_time
264
print(f"Post-clear access took {refresh_time:.3f} seconds")
265
print(f"New path: {ca_path3}")
266
267
# Run caching demonstration
268
demonstrate_caching()
269
```