CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-cryptography

Cryptographic recipes and primitives for Python developers

Pending
Overview
Eval results
Files

x509-certificates.mddocs/

X.509 Certificates

Comprehensive X.509 certificate handling including certificate creation, parsing, validation, and extension management. Supports certificate signing requests (CSRs), certificate revocation lists (CRLs), and certificate verification workflows.

Core Imports

from cryptography import x509
from cryptography.x509.oid import NameOID, ExtensionOID, SignatureAlgorithmOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa

Capabilities

Certificate Loading and Parsing

Load and parse X.509 certificates from various formats.

def load_pem_x509_certificate(data: bytes) -> Certificate:
    """
    Load X.509 certificate from PEM format.
    
    Args:
        data (bytes): PEM-encoded certificate data
        
    Returns:
        Certificate: Parsed certificate object
    """

def load_der_x509_certificate(data: bytes) -> Certificate:
    """
    Load X.509 certificate from DER format.
    
    Args:
        data (bytes): DER-encoded certificate data
        
    Returns:
        Certificate: Parsed certificate object
    """

def load_pem_x509_certificates(data: bytes) -> List[Certificate]:
    """
    Load multiple X.509 certificates from PEM format.
    
    Args:
        data (bytes): PEM data containing multiple certificates
        
    Returns:
        List[Certificate]: List of parsed certificate objects
    """

Certificate Objects

class Certificate:
    def public_key(self):
        """
        Get the certificate's public key.
        
        Returns:
            PublicKey: The public key (RSA, DSA, EC, Ed25519, Ed448, etc.)
        """
    
    @property
    def subject(self) -> Name:
        """Certificate subject name"""
    
    @property
    def issuer(self) -> Name:
        """Certificate issuer name"""
    
    @property
    def serial_number(self) -> int:
        """Certificate serial number"""
    
    @property
    def version(self) -> Version:
        """Certificate version (typically Version.v3)"""
    
    @property
    def not_valid_before(self) -> datetime:
        """Certificate validity start time"""
    
    @property
    def not_valid_after(self) -> datetime:
        """Certificate validity end time"""
    
    @property
    def signature_algorithm_oid(self) -> ObjectIdentifier:
        """OID of signature algorithm used"""
    
    @property
    def signature_hash_algorithm(self):
        """Hash algorithm used in signature"""
    
    @property
    def extensions(self) -> Extensions:
        """Certificate extensions"""
    
    def fingerprint(self, algorithm) -> bytes:
        """
        Calculate certificate fingerprint.
        
        Args:
            algorithm: Hash algorithm (e.g., hashes.SHA256())
            
        Returns:
            bytes: Certificate fingerprint
        """
    
    def public_bytes(self, encoding: Encoding) -> bytes:
        """
        Serialize certificate to bytes.
        
        Args:
            encoding: Encoding format (PEM or DER)
            
        Returns:
            bytes: Serialized certificate
        """

Certificate Creation

class CertificateBuilder:
    def subject_name(self, name: Name) -> 'CertificateBuilder':
        """Set certificate subject name"""
    
    def issuer_name(self, name: Name) -> 'CertificateBuilder':
        """Set certificate issuer name"""
    
    def public_key(self, key) -> 'CertificateBuilder':
        """Set certificate public key"""
    
    def serial_number(self, serial: int) -> 'CertificateBuilder':
        """Set certificate serial number"""
    
    def not_valid_before(self, time: datetime) -> 'CertificateBuilder':
        """Set certificate validity start time"""
    
    def not_valid_after(self, time: datetime) -> 'CertificateBuilder':
        """Set certificate validity end time"""
    
    def add_extension(self, extension, critical: bool) -> 'CertificateBuilder':
        """Add extension to certificate"""
    
    def sign(self, private_key, algorithm) -> Certificate:
        """
        Sign and build the certificate.
        
        Args:
            private_key: Private key for signing
            algorithm: Hash algorithm (e.g., hashes.SHA256())
            
        Returns:
            Certificate: Signed certificate
        """

def random_serial_number() -> int:
    """Generate cryptographically secure random serial number"""

Distinguished Names

class Name:
    def __init__(self, attributes: List[NameAttribute]):
        """
        Create distinguished name from attributes.
        
        Args:
            attributes: List of name attributes
        """
    
    def rfc4514_string(self) -> str:
        """RFC 4514 string representation"""
    
    def get_attributes_for_oid(self, oid: ObjectIdentifier) -> List[NameAttribute]:
        """Get all attributes matching an OID"""

class NameAttribute:
    def __init__(self, oid: ObjectIdentifier, value: str):
        """
        Create name attribute.
        
        Args:
            oid: Attribute OID (e.g., NameOID.COMMON_NAME)
            value: Attribute value
        """
    
    @property
    def oid(self) -> ObjectIdentifier:
        """Attribute OID"""
    
    @property
    def value(self) -> str:
        """Attribute value"""

class RelativeDistinguishedName:
    def __init__(self, attributes: List[NameAttribute]):
        """Create RDN from attributes"""
    
    def get_attributes_for_oid(self, oid: ObjectIdentifier) -> List[NameAttribute]:
        """Get attributes for specific OID"""

Certificate Extensions

class Extensions:
    def get_extension_for_oid(self, oid: ObjectIdentifier) -> Extension:
        """Get extension by OID"""
    
    def __iter__(self):
        """Iterate over all extensions"""

class Extension:
    @property
    def oid(self) -> ObjectIdentifier:
        """Extension OID"""
    
    @property
    def critical(self) -> bool:
        """Whether extension is critical"""
    
    @property
    def value(self) -> ExtensionType:
        """Extension value object"""

class BasicConstraints:
    def __init__(self, ca: bool, path_length: int = None):
        """
        Basic constraints extension.
        
        Args:
            ca: Whether this is a CA certificate
            path_length: Maximum path length for intermediate CAs
        """
    
    @property
    def ca(self) -> bool:
        """Is this a CA certificate"""
    
    @property
    def path_length(self) -> int:
        """Path length constraint"""

class KeyUsage:
    def __init__(self, digital_signature: bool = False, key_agreement: bool = False, 
                 key_cert_sign: bool = False, crl_sign: bool = False,
                 content_commitment: bool = False, data_encipherment: bool = False,
                 key_encipherment: bool = False, encipher_only: bool = False,
                 decipher_only: bool = False):
        """Key usage extension indicating allowed key operations"""

class SubjectAlternativeName:
    def __init__(self, general_names: List[GeneralName]):
        """Subject alternative name extension"""
    
    def get_values_for_type(self, type_: type) -> List:
        """Get values for specific general name type"""

class AuthorityKeyIdentifier:
    def __init__(self, key_identifier: bytes = None, 
                 authority_cert_issuer: List[GeneralName] = None,
                 authority_cert_serial_number: int = None):
        """Authority key identifier extension"""

class SubjectKeyIdentifier:
    def __init__(self, digest: bytes):
        """Subject key identifier extension"""
    
    @property
    def digest(self) -> bytes:
        """Key identifier digest"""

General Names

class GeneralName:
    """Abstract base for general name types"""

class DNSName:
    def __init__(self, value: str):
        """DNS name general name"""
    
    @property
    def value(self) -> str:
        """DNS name value"""

class IPAddress:
    def __init__(self, value):
        """IP address general name (IPv4/IPv6 address or network)"""
    
    @property
    def value(self):
        """IP address value"""

class RFC822Name:
    def __init__(self, value: str):
        """Email address general name"""
    
    @property
    def value(self) -> str:
        """Email address"""

class UniformResourceIdentifier:
    def __init__(self, value: str):
        """URI general name"""
    
    @property
    def value(self) -> str:
        """URI value"""

class DirectoryName:
    def __init__(self, value: Name):
        """Directory name (distinguished name) general name"""
    
    @property
    def value(self) -> Name:
        """Distinguished name"""

Certificate Signing Requests (CSRs)

def load_pem_x509_csr(data: bytes) -> CertificateSigningRequest:
    """Load CSR from PEM format"""

def load_der_x509_csr(data: bytes) -> CertificateSigningRequest:
    """Load CSR from DER format"""

class CertificateSigningRequest:
    @property
    def subject(self) -> Name:
        """CSR subject name"""
    
    def public_key(self):
        """CSR public key"""
    
    @property
    def signature_algorithm_oid(self) -> ObjectIdentifier:
        """Signature algorithm OID"""
    
    @property
    def extensions(self) -> Extensions:
        """CSR extension requests"""
    
    def is_signature_valid(self) -> bool:
        """Verify CSR signature"""

class CertificateSigningRequestBuilder:
    def subject_name(self, name: Name) -> 'CertificateSigningRequestBuilder':
        """Set CSR subject"""
    
    def add_extension(self, extension, critical: bool) -> 'CertificateSigningRequestBuilder':
        """Add extension request"""
    
    def sign(self, private_key, algorithm) -> CertificateSigningRequest:
        """Sign and build CSR"""

Certificate Revocation Lists (CRLs)

def load_pem_x509_crl(data: bytes) -> CertificateRevocationList:
    """Load CRL from PEM format"""

def load_der_x509_crl(data: bytes) -> CertificateRevocationList:
    """Load CRL from DER format"""

class CertificateRevocationList:
    @property
    def issuer(self) -> Name:
        """CRL issuer"""
    
    @property
    def last_update(self) -> datetime:
        """CRL last update time"""
    
    @property
    def next_update(self) -> datetime:
        """CRL next update time"""
    
    def get_revoked_certificate_by_serial_number(self, serial: int) -> RevokedCertificate:
        """Get revoked certificate by serial number"""
    
    def __iter__(self):
        """Iterate over revoked certificates"""

class RevokedCertificate:
    @property
    def serial_number(self) -> int:
        """Serial number of revoked certificate"""
    
    @property
    def revocation_date(self) -> datetime:
        """Date certificate was revoked"""
    
    @property
    def extensions(self) -> Extensions:
        """Revocation entry extensions"""

Usage Examples

Loading and Inspecting Certificates

from cryptography import x509
from cryptography.x509.oid import NameOID

# Load certificate from PEM file
with open('certificate.pem', 'rb') as f:
    cert_data = f.read()

cert = x509.load_pem_x509_certificate(cert_data)

# Inspect certificate details
print(f"Subject: {cert.subject.rfc4514_string()}")
print(f"Issuer: {cert.issuer.rfc4514_string()}")
print(f"Serial: {cert.serial_number}")
print(f"Valid from: {cert.not_valid_before}")
print(f"Valid to: {cert.not_valid_after}")

# Extract common name
cn_attributes = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)
if cn_attributes:
    print(f"Common Name: {cn_attributes[0].value}")

# Check extensions
try:
    san_ext = cert.extensions.get_extension_for_oid(ExtensionOID.SUBJECT_ALTERNATIVE_NAME)
    san = san_ext.value
    dns_names = san.get_values_for_type(x509.DNSName)
    print(f"DNS SANs: {[name.value for name in dns_names]}")
except x509.ExtensionNotFound:
    print("No SAN extension found")

Creating a Self-Signed Certificate

from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
import datetime

# Generate private key
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048
)

# Create certificate
subject = issuer = x509.Name([
    x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
    x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "California"),
    x509.NameAttribute(NameOID.LOCALITY_NAME, "San Francisco"),
    x509.NameAttribute(NameOID.ORGANIZATION_NAME, "My Company"),
    x509.NameAttribute(NameOID.COMMON_NAME, "mysite.com"),
])

cert = x509.CertificateBuilder().subject_name(
    subject
).issuer_name(
    issuer
).public_key(
    private_key.public_key()
).serial_number(
    x509.random_serial_number()
).not_valid_before(
    datetime.datetime.utcnow()
).not_valid_after(
    datetime.datetime.utcnow() + datetime.timedelta(days=365)
).add_extension(
    x509.SubjectAlternativeName([
        x509.DNSName("mysite.com"),
        x509.DNSName("www.mysite.com"),
    ]),
    critical=False,
).add_extension(
    x509.BasicConstraints(ca=False, path_length=None),
    critical=True,
).sign(private_key, hashes.SHA256())

# Save certificate and key
cert_pem = cert.public_bytes(Encoding.PEM)
key_pem = private_key.private_bytes(
    encoding=Encoding.PEM,
    format=PrivateFormat.PKCS8,
    encryption_algorithm=NoEncryption()
)

with open('certificate.pem', 'wb') as f:
    f.write(cert_pem)

with open('private_key.pem', 'wb') as f:
    f.write(key_pem)

Creating a Certificate Signing Request

from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa

# Generate private key
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048
)

# Create CSR
subject = x509.Name([
    x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
    x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "California"),
    x509.NameAttribute(NameOID.LOCALITY_NAME, "San Francisco"),
    x509.NameAttribute(NameOID.ORGANIZATION_NAME, "My Company"),
    x509.NameAttribute(NameOID.COMMON_NAME, "example.com"),
])

csr = x509.CertificateSigningRequestBuilder().subject_name(
    subject
).add_extension(
    x509.SubjectAlternativeName([
        x509.DNSName("example.com"),
        x509.DNSName("www.example.com"),
    ]),
    critical=False,
).sign(private_key, hashes.SHA256())

# Save CSR
csr_pem = csr.public_bytes(Encoding.PEM)
with open('csr.pem', 'wb') as f:
    f.write(csr_pem)

# Verify CSR signature
print(f"CSR signature valid: {csr.is_signature_valid()}")

Certificate Chain Validation

from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

def verify_certificate_chain(cert_chain):
    """Verify a certificate chain"""
    for i in range(len(cert_chain) - 1):
        cert = cert_chain[i]
        issuer_cert = cert_chain[i + 1]
        
        # Verify issuer name matches subject
        if cert.issuer != issuer_cert.subject:
            return False, f"Issuer name mismatch at position {i}"
        
        # Verify signature
        try:
            issuer_public_key = issuer_cert.public_key()
            issuer_public_key.verify(
                cert.signature,
                cert.tbs_certificate_bytes,
                padding.PKCS1v15(),
                cert.signature_hash_algorithm
            )
        except Exception as e:
            return False, f"Signature verification failed at position {i}: {e}"
    
    return True, "Chain verification successful"

# Usage
with open('cert_chain.pem', 'rb') as f:
    chain_data = f.read()

cert_chain = x509.load_pem_x509_certificates(chain_data)
valid, message = verify_certificate_chain(cert_chain)
print(f"Chain valid: {valid}, Message: {message}")

OID Constants

Common object identifiers for names and extensions:

class NameOID:
    COMMON_NAME: ObjectIdentifier
    COUNTRY_NAME: ObjectIdentifier
    LOCALITY_NAME: ObjectIdentifier
    STATE_OR_PROVINCE_NAME: ObjectIdentifier
    ORGANIZATION_NAME: ObjectIdentifier
    ORGANIZATIONAL_UNIT_NAME: ObjectIdentifier
    EMAIL_ADDRESS: ObjectIdentifier

class ExtensionOID:
    BASIC_CONSTRAINTS: ObjectIdentifier
    KEY_USAGE: ObjectIdentifier
    EXTENDED_KEY_USAGE: ObjectIdentifier
    SUBJECT_ALTERNATIVE_NAME: ObjectIdentifier
    ISSUER_ALTERNATIVE_NAME: ObjectIdentifier
    SUBJECT_KEY_IDENTIFIER: ObjectIdentifier
    AUTHORITY_KEY_IDENTIFIER: ObjectIdentifier
    CRL_DISTRIBUTION_POINTS: ObjectIdentifier
    AUTHORITY_INFORMATION_ACCESS: ObjectIdentifier
    CERTIFICATE_POLICIES: ObjectIdentifier

class SignatureAlgorithmOID:
    RSA_WITH_SHA256: ObjectIdentifier
    RSA_WITH_SHA384: ObjectIdentifier
    RSA_WITH_SHA512: ObjectIdentifier
    ECDSA_WITH_SHA256: ObjectIdentifier
    ECDSA_WITH_SHA384: ObjectIdentifier
    ECDSA_WITH_SHA512: ObjectIdentifier

Exception Handling

class InvalidVersion(ValueError):
    """Invalid certificate version"""

class ExtensionNotFound(ValueError):
    """Certificate extension not found"""

class DuplicateExtension(ValueError):
    """Duplicate extension in certificate"""

class UnsupportedGeneralNameType(ValueError):
    """Unsupported general name type"""

Install with Tessl CLI

npx tessl i tessl/pypi-cryptography

docs

aead-ciphers.md

asymmetric-cryptography.md

hash-functions.md

index.md

key-derivation.md

key-serialization.md

message-authentication.md

symmetric-ciphers.md

symmetric-encryption.md

two-factor-auth.md

utilities.md

x509-certificates.md

tile.json