Cross-platform cryptographic library providing TLS sockets, asymmetric/symmetric encryption, and key operations using OS-native crypto libraries
—
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.
from oscrypto import trust_list
from oscrypto.errors import CACertsErrorRetrieve CA certificates from the operating system's trust store.
def get_list() -> List[Certificate]:
"""
Get list of CA certificates from the OS trust store.
Returns:
List of Certificate objects representing trusted CA certificates
Raises:
CACertsError if unable to export certificates from OS trust store
"""
def get_path() -> str:
"""
Get path to a CA certificate bundle file in PEM format.
Returns:
String path to a temporary PEM file containing CA certificates
Note:
The returned file is cached and may be automatically cleaned up.
Copy the file if you need persistent access.
"""
def clear_cache() -> None:
"""
Clear cached CA certificate data and temporary files.
Note:
Forces regeneration of CA bundle on next access.
"""from oscrypto import trust_list
# Get CA certificates as Certificate objects
ca_certs = trust_list.get_list()
print(f"Found {len(ca_certs)} CA certificates in OS trust store")
# Examine a few certificates
for i, cert in enumerate(ca_certs[:3]):
print(f"CA {i+1}: {cert.subject}")
print(f" Issuer: {cert.issuer}")
print(f" Valid until: {cert.not_valid_after}")
print()from oscrypto import trust_list
import shutil
# Get path to PEM bundle file
pem_path = trust_list.get_path()
print(f"CA bundle available at: {pem_path}")
# Copy to persistent location
persistent_path = "/etc/ssl/oscrypto-ca-bundle.pem"
try:
shutil.copy2(pem_path, persistent_path)
print(f"CA bundle copied to: {persistent_path}")
except PermissionError:
print("Permission denied - run as administrator/root")
# Read PEM content
with open(pem_path, 'r') as f:
pem_data = f.read()
cert_count = pem_data.count('-----BEGIN CERTIFICATE-----')
print(f"PEM bundle contains {cert_count} certificates")from oscrypto import trust_list
import ssl
import socket
# Get CA bundle path for use with Python's ssl module
ca_bundle_path = trust_list.get_path()
# Create SSL context with OS trust roots
context = ssl.create_default_context(cafile=ca_bundle_path)
# Use with HTTPS connections
with socket.create_connection(('www.example.com', 443)) as sock:
with context.wrap_socket(sock, server_hostname='www.example.com') as ssock:
print(f"SSL version: {ssock.version()}")
print(f"Cipher: {ssock.cipher()}")
# Send HTTP request
ssock.send(b'GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n')
response = ssock.recv(1024)
print(f"Response: {response[:100]}...")from oscrypto import trust_list
from collections import defaultdict
import datetime
def analyze_trust_store():
"""Analyze CA certificates in the trust store."""
ca_certs = trust_list.get_list()
# Group by issuer
issuers = defaultdict(int)
key_sizes = defaultdict(int)
expiring_soon = []
now = datetime.datetime.now()
one_year = datetime.timedelta(days=365)
for cert in ca_certs:
# Count by issuer
issuer_cn = cert.issuer.get('common_name', 'Unknown')
issuers[issuer_cn] += 1
# Analyze key sizes
if hasattr(cert.public_key, 'bit_size'):
key_sizes[cert.public_key.bit_size] += 1
# Check expiration
if cert.not_valid_after and cert.not_valid_after < now + one_year:
expiring_soon.append((cert.subject.get('common_name', 'Unknown'), cert.not_valid_after))
print(f"Trust Store Analysis ({len(ca_certs)} certificates)")
print("=" * 50)
print("Top 10 Certificate Issuers:")
for issuer, count in sorted(issuers.items(), key=lambda x: x[1], reverse=True)[:10]:
print(f" {issuer}: {count} certificates")
print("\nKey Size Distribution:")
for size, count in sorted(key_sizes.items()):
print(f" {size}-bit: {count} certificates")
if expiring_soon:
print(f"\nCertificates expiring within 1 year ({len(expiring_soon)}):")
for name, expiry in sorted(expiring_soon, key=lambda x: x[1])[:5]:
print(f" {name}: expires {expiry.strftime('%Y-%m-%d')}")
# Run analysis
analyze_trust_store()from oscrypto import trust_list, asymmetric
import tempfile
import os
def create_custom_ca_bundle(extra_certs_paths: list) -> str:
"""Create a custom CA bundle combining OS certs with additional ones."""
# Get OS CA certificates
os_ca_path = trust_list.get_path()
# Read OS CA bundle
with open(os_ca_path, 'r') as f:
ca_bundle_content = f.read()
# Add custom certificates
for cert_path in extra_certs_paths:
if os.path.exists(cert_path):
with open(cert_path, 'rb') as f:
cert_data = f.read()
# Load and validate certificate
try:
cert = asymmetric.load_certificate(cert_data)
print(f"Adding custom CA: {cert.subject}")
# Convert to PEM if needed
if cert_data.startswith(b'-----BEGIN'):
ca_bundle_content += "\n" + cert_data.decode('utf-8')
else:
# Convert DER to PEM
pem_cert = asymmetric.dump_certificate(cert)
pem_lines = [
"-----BEGIN CERTIFICATE-----",
pem_cert.b64encode().decode('ascii'),
"-----END CERTIFICATE-----"
]
ca_bundle_content += "\n" + "\n".join(pem_lines) + "\n"
except Exception as e:
print(f"Failed to load certificate {cert_path}: {e}")
# Write combined bundle to temporary file
with tempfile.NamedTemporaryFile(mode='w', suffix='.pem', delete=False) as f:
f.write(ca_bundle_content)
custom_bundle_path = f.name
print(f"Custom CA bundle created: {custom_bundle_path}")
return custom_bundle_path
# Example usage
custom_certs = [
'/path/to/internal-ca.pem',
'/path/to/test-ca.crt'
]
custom_bundle = create_custom_ca_bundle(custom_certs)from oscrypto import trust_list
import time
import os
def demonstrate_caching():
"""Demonstrate trust store caching behavior."""
print("Initial trust store access...")
start_time = time.time()
ca_path1 = trust_list.get_path()
initial_time = time.time() - start_time
print(f"First access took {initial_time:.3f} seconds")
print(f"Bundle path: {ca_path1}")
print(f"Bundle size: {os.path.getsize(ca_path1)} bytes")
print("\nSecond access (cached)...")
start_time = time.time()
ca_path2 = trust_list.get_path()
cached_time = time.time() - start_time
print(f"Cached access took {cached_time:.3f} seconds")
print(f"Same path: {ca_path1 == ca_path2}")
print(f"\nCaching speedup: {initial_time / cached_time:.1f}x faster")
print("\nClearing cache...")
trust_list.clear_cache()
print("Post-clear access...")
start_time = time.time()
ca_path3 = trust_list.get_path()
refresh_time = time.time() - start_time
print(f"Post-clear access took {refresh_time:.3f} seconds")
print(f"New path: {ca_path3}")
# Run caching demonstration
demonstrate_caching()Install with Tessl CLI
npx tessl i tessl/pypi-oscrypto