or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

aead-ciphers.mdasymmetric-cryptography.mdhash-functions.mdindex.mdkey-derivation.mdkey-serialization.mdmessage-authentication.mdsymmetric-ciphers.mdsymmetric-encryption.mdtwo-factor-auth.mdutilities.mdx509-certificates.md

x509-certificates.mddocs/

0

# X.509 Certificates

1

2

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.

3

4

## Core Imports

5

6

```python

7

from cryptography import x509

8

from cryptography.x509.oid import NameOID, ExtensionOID, SignatureAlgorithmOID

9

from cryptography.hazmat.primitives import hashes

10

from cryptography.hazmat.primitives.asymmetric import rsa

11

```

12

13

## Capabilities

14

15

### Certificate Loading and Parsing

16

17

Load and parse X.509 certificates from various formats.

18

19

```python { .api }

20

def load_pem_x509_certificate(data: bytes) -> Certificate:

21

"""

22

Load X.509 certificate from PEM format.

23

24

Args:

25

data (bytes): PEM-encoded certificate data

26

27

Returns:

28

Certificate: Parsed certificate object

29

"""

30

31

def load_der_x509_certificate(data: bytes) -> Certificate:

32

"""

33

Load X.509 certificate from DER format.

34

35

Args:

36

data (bytes): DER-encoded certificate data

37

38

Returns:

39

Certificate: Parsed certificate object

40

"""

41

42

def load_pem_x509_certificates(data: bytes) -> List[Certificate]:

43

"""

44

Load multiple X.509 certificates from PEM format.

45

46

Args:

47

data (bytes): PEM data containing multiple certificates

48

49

Returns:

50

List[Certificate]: List of parsed certificate objects

51

"""

52

```

53

54

### Certificate Objects

55

56

```python { .api }

57

class Certificate:

58

def public_key(self):

59

"""

60

Get the certificate's public key.

61

62

Returns:

63

PublicKey: The public key (RSA, DSA, EC, Ed25519, Ed448, etc.)

64

"""

65

66

@property

67

def subject(self) -> Name:

68

"""Certificate subject name"""

69

70

@property

71

def issuer(self) -> Name:

72

"""Certificate issuer name"""

73

74

@property

75

def serial_number(self) -> int:

76

"""Certificate serial number"""

77

78

@property

79

def version(self) -> Version:

80

"""Certificate version (typically Version.v3)"""

81

82

@property

83

def not_valid_before(self) -> datetime:

84

"""Certificate validity start time"""

85

86

@property

87

def not_valid_after(self) -> datetime:

88

"""Certificate validity end time"""

89

90

@property

91

def signature_algorithm_oid(self) -> ObjectIdentifier:

92

"""OID of signature algorithm used"""

93

94

@property

95

def signature_hash_algorithm(self):

96

"""Hash algorithm used in signature"""

97

98

@property

99

def extensions(self) -> Extensions:

100

"""Certificate extensions"""

101

102

def fingerprint(self, algorithm) -> bytes:

103

"""

104

Calculate certificate fingerprint.

105

106

Args:

107

algorithm: Hash algorithm (e.g., hashes.SHA256())

108

109

Returns:

110

bytes: Certificate fingerprint

111

"""

112

113

def public_bytes(self, encoding: Encoding) -> bytes:

114

"""

115

Serialize certificate to bytes.

116

117

Args:

118

encoding: Encoding format (PEM or DER)

119

120

Returns:

121

bytes: Serialized certificate

122

"""

123

```

124

125

### Certificate Creation

126

127

```python { .api }

128

class CertificateBuilder:

129

def subject_name(self, name: Name) -> 'CertificateBuilder':

130

"""Set certificate subject name"""

131

132

def issuer_name(self, name: Name) -> 'CertificateBuilder':

133

"""Set certificate issuer name"""

134

135

def public_key(self, key) -> 'CertificateBuilder':

136

"""Set certificate public key"""

137

138

def serial_number(self, serial: int) -> 'CertificateBuilder':

139

"""Set certificate serial number"""

140

141

def not_valid_before(self, time: datetime) -> 'CertificateBuilder':

142

"""Set certificate validity start time"""

143

144

def not_valid_after(self, time: datetime) -> 'CertificateBuilder':

145

"""Set certificate validity end time"""

146

147

def add_extension(self, extension, critical: bool) -> 'CertificateBuilder':

148

"""Add extension to certificate"""

149

150

def sign(self, private_key, algorithm) -> Certificate:

151

"""

152

Sign and build the certificate.

153

154

Args:

155

private_key: Private key for signing

156

algorithm: Hash algorithm (e.g., hashes.SHA256())

157

158

Returns:

159

Certificate: Signed certificate

160

"""

161

162

def random_serial_number() -> int:

163

"""Generate cryptographically secure random serial number"""

164

```

165

166

### Distinguished Names

167

168

```python { .api }

169

class Name:

170

def __init__(self, attributes: List[NameAttribute]):

171

"""

172

Create distinguished name from attributes.

173

174

Args:

175

attributes: List of name attributes

176

"""

177

178

def rfc4514_string(self) -> str:

179

"""RFC 4514 string representation"""

180

181

def get_attributes_for_oid(self, oid: ObjectIdentifier) -> List[NameAttribute]:

182

"""Get all attributes matching an OID"""

183

184

class NameAttribute:

185

def __init__(self, oid: ObjectIdentifier, value: str):

186

"""

187

Create name attribute.

188

189

Args:

190

oid: Attribute OID (e.g., NameOID.COMMON_NAME)

191

value: Attribute value

192

"""

193

194

@property

195

def oid(self) -> ObjectIdentifier:

196

"""Attribute OID"""

197

198

@property

199

def value(self) -> str:

200

"""Attribute value"""

201

202

class RelativeDistinguishedName:

203

def __init__(self, attributes: List[NameAttribute]):

204

"""Create RDN from attributes"""

205

206

def get_attributes_for_oid(self, oid: ObjectIdentifier) -> List[NameAttribute]:

207

"""Get attributes for specific OID"""

208

```

209

210

### Certificate Extensions

211

212

```python { .api }

213

class Extensions:

214

def get_extension_for_oid(self, oid: ObjectIdentifier) -> Extension:

215

"""Get extension by OID"""

216

217

def __iter__(self):

218

"""Iterate over all extensions"""

219

220

class Extension:

221

@property

222

def oid(self) -> ObjectIdentifier:

223

"""Extension OID"""

224

225

@property

226

def critical(self) -> bool:

227

"""Whether extension is critical"""

228

229

@property

230

def value(self) -> ExtensionType:

231

"""Extension value object"""

232

233

class BasicConstraints:

234

def __init__(self, ca: bool, path_length: int = None):

235

"""

236

Basic constraints extension.

237

238

Args:

239

ca: Whether this is a CA certificate

240

path_length: Maximum path length for intermediate CAs

241

"""

242

243

@property

244

def ca(self) -> bool:

245

"""Is this a CA certificate"""

246

247

@property

248

def path_length(self) -> int:

249

"""Path length constraint"""

250

251

class KeyUsage:

252

def __init__(self, digital_signature: bool = False, key_agreement: bool = False,

253

key_cert_sign: bool = False, crl_sign: bool = False,

254

content_commitment: bool = False, data_encipherment: bool = False,

255

key_encipherment: bool = False, encipher_only: bool = False,

256

decipher_only: bool = False):

257

"""Key usage extension indicating allowed key operations"""

258

259

class SubjectAlternativeName:

260

def __init__(self, general_names: List[GeneralName]):

261

"""Subject alternative name extension"""

262

263

def get_values_for_type(self, type_: type) -> List:

264

"""Get values for specific general name type"""

265

266

class AuthorityKeyIdentifier:

267

def __init__(self, key_identifier: bytes = None,

268

authority_cert_issuer: List[GeneralName] = None,

269

authority_cert_serial_number: int = None):

270

"""Authority key identifier extension"""

271

272

class SubjectKeyIdentifier:

273

def __init__(self, digest: bytes):

274

"""Subject key identifier extension"""

275

276

@property

277

def digest(self) -> bytes:

278

"""Key identifier digest"""

279

```

280

281

### General Names

282

283

```python { .api }

284

class GeneralName:

285

"""Abstract base for general name types"""

286

287

class DNSName:

288

def __init__(self, value: str):

289

"""DNS name general name"""

290

291

@property

292

def value(self) -> str:

293

"""DNS name value"""

294

295

class IPAddress:

296

def __init__(self, value):

297

"""IP address general name (IPv4/IPv6 address or network)"""

298

299

@property

300

def value(self):

301

"""IP address value"""

302

303

class RFC822Name:

304

def __init__(self, value: str):

305

"""Email address general name"""

306

307

@property

308

def value(self) -> str:

309

"""Email address"""

310

311

class UniformResourceIdentifier:

312

def __init__(self, value: str):

313

"""URI general name"""

314

315

@property

316

def value(self) -> str:

317

"""URI value"""

318

319

class DirectoryName:

320

def __init__(self, value: Name):

321

"""Directory name (distinguished name) general name"""

322

323

@property

324

def value(self) -> Name:

325

"""Distinguished name"""

326

```

327

328

### Certificate Signing Requests (CSRs)

329

330

```python { .api }

331

def load_pem_x509_csr(data: bytes) -> CertificateSigningRequest:

332

"""Load CSR from PEM format"""

333

334

def load_der_x509_csr(data: bytes) -> CertificateSigningRequest:

335

"""Load CSR from DER format"""

336

337

class CertificateSigningRequest:

338

@property

339

def subject(self) -> Name:

340

"""CSR subject name"""

341

342

def public_key(self):

343

"""CSR public key"""

344

345

@property

346

def signature_algorithm_oid(self) -> ObjectIdentifier:

347

"""Signature algorithm OID"""

348

349

@property

350

def extensions(self) -> Extensions:

351

"""CSR extension requests"""

352

353

def is_signature_valid(self) -> bool:

354

"""Verify CSR signature"""

355

356

class CertificateSigningRequestBuilder:

357

def subject_name(self, name: Name) -> 'CertificateSigningRequestBuilder':

358

"""Set CSR subject"""

359

360

def add_extension(self, extension, critical: bool) -> 'CertificateSigningRequestBuilder':

361

"""Add extension request"""

362

363

def sign(self, private_key, algorithm) -> CertificateSigningRequest:

364

"""Sign and build CSR"""

365

```

366

367

### Certificate Revocation Lists (CRLs)

368

369

```python { .api }

370

def load_pem_x509_crl(data: bytes) -> CertificateRevocationList:

371

"""Load CRL from PEM format"""

372

373

def load_der_x509_crl(data: bytes) -> CertificateRevocationList:

374

"""Load CRL from DER format"""

375

376

class CertificateRevocationList:

377

@property

378

def issuer(self) -> Name:

379

"""CRL issuer"""

380

381

@property

382

def last_update(self) -> datetime:

383

"""CRL last update time"""

384

385

@property

386

def next_update(self) -> datetime:

387

"""CRL next update time"""

388

389

def get_revoked_certificate_by_serial_number(self, serial: int) -> RevokedCertificate:

390

"""Get revoked certificate by serial number"""

391

392

def __iter__(self):

393

"""Iterate over revoked certificates"""

394

395

class RevokedCertificate:

396

@property

397

def serial_number(self) -> int:

398

"""Serial number of revoked certificate"""

399

400

@property

401

def revocation_date(self) -> datetime:

402

"""Date certificate was revoked"""

403

404

@property

405

def extensions(self) -> Extensions:

406

"""Revocation entry extensions"""

407

```

408

409

## Usage Examples

410

411

### Loading and Inspecting Certificates

412

413

```python

414

from cryptography import x509

415

from cryptography.x509.oid import NameOID

416

417

# Load certificate from PEM file

418

with open('certificate.pem', 'rb') as f:

419

cert_data = f.read()

420

421

cert = x509.load_pem_x509_certificate(cert_data)

422

423

# Inspect certificate details

424

print(f"Subject: {cert.subject.rfc4514_string()}")

425

print(f"Issuer: {cert.issuer.rfc4514_string()}")

426

print(f"Serial: {cert.serial_number}")

427

print(f"Valid from: {cert.not_valid_before}")

428

print(f"Valid to: {cert.not_valid_after}")

429

430

# Extract common name

431

cn_attributes = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)

432

if cn_attributes:

433

print(f"Common Name: {cn_attributes[0].value}")

434

435

# Check extensions

436

try:

437

san_ext = cert.extensions.get_extension_for_oid(ExtensionOID.SUBJECT_ALTERNATIVE_NAME)

438

san = san_ext.value

439

dns_names = san.get_values_for_type(x509.DNSName)

440

print(f"DNS SANs: {[name.value for name in dns_names]}")

441

except x509.ExtensionNotFound:

442

print("No SAN extension found")

443

```

444

445

### Creating a Self-Signed Certificate

446

447

```python

448

from cryptography import x509

449

from cryptography.x509.oid import NameOID

450

from cryptography.hazmat.primitives import hashes

451

from cryptography.hazmat.primitives.asymmetric import rsa

452

from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption

453

import datetime

454

455

# Generate private key

456

private_key = rsa.generate_private_key(

457

public_exponent=65537,

458

key_size=2048

459

)

460

461

# Create certificate

462

subject = issuer = x509.Name([

463

x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),

464

x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "California"),

465

x509.NameAttribute(NameOID.LOCALITY_NAME, "San Francisco"),

466

x509.NameAttribute(NameOID.ORGANIZATION_NAME, "My Company"),

467

x509.NameAttribute(NameOID.COMMON_NAME, "mysite.com"),

468

])

469

470

cert = x509.CertificateBuilder().subject_name(

471

subject

472

).issuer_name(

473

issuer

474

).public_key(

475

private_key.public_key()

476

).serial_number(

477

x509.random_serial_number()

478

).not_valid_before(

479

datetime.datetime.utcnow()

480

).not_valid_after(

481

datetime.datetime.utcnow() + datetime.timedelta(days=365)

482

).add_extension(

483

x509.SubjectAlternativeName([

484

x509.DNSName("mysite.com"),

485

x509.DNSName("www.mysite.com"),

486

]),

487

critical=False,

488

).add_extension(

489

x509.BasicConstraints(ca=False, path_length=None),

490

critical=True,

491

).sign(private_key, hashes.SHA256())

492

493

# Save certificate and key

494

cert_pem = cert.public_bytes(Encoding.PEM)

495

key_pem = private_key.private_bytes(

496

encoding=Encoding.PEM,

497

format=PrivateFormat.PKCS8,

498

encryption_algorithm=NoEncryption()

499

)

500

501

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

502

f.write(cert_pem)

503

504

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

505

f.write(key_pem)

506

```

507

508

### Creating a Certificate Signing Request

509

510

```python

511

from cryptography import x509

512

from cryptography.x509.oid import NameOID

513

from cryptography.hazmat.primitives import hashes

514

from cryptography.hazmat.primitives.asymmetric import rsa

515

516

# Generate private key

517

private_key = rsa.generate_private_key(

518

public_exponent=65537,

519

key_size=2048

520

)

521

522

# Create CSR

523

subject = x509.Name([

524

x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),

525

x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "California"),

526

x509.NameAttribute(NameOID.LOCALITY_NAME, "San Francisco"),

527

x509.NameAttribute(NameOID.ORGANIZATION_NAME, "My Company"),

528

x509.NameAttribute(NameOID.COMMON_NAME, "example.com"),

529

])

530

531

csr = x509.CertificateSigningRequestBuilder().subject_name(

532

subject

533

).add_extension(

534

x509.SubjectAlternativeName([

535

x509.DNSName("example.com"),

536

x509.DNSName("www.example.com"),

537

]),

538

critical=False,

539

).sign(private_key, hashes.SHA256())

540

541

# Save CSR

542

csr_pem = csr.public_bytes(Encoding.PEM)

543

with open('csr.pem', 'wb') as f:

544

f.write(csr_pem)

545

546

# Verify CSR signature

547

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

548

```

549

550

### Certificate Chain Validation

551

552

```python

553

from cryptography import x509

554

from cryptography.hazmat.primitives import hashes

555

from cryptography.hazmat.primitives.asymmetric import padding

556

557

def verify_certificate_chain(cert_chain):

558

"""Verify a certificate chain"""

559

for i in range(len(cert_chain) - 1):

560

cert = cert_chain[i]

561

issuer_cert = cert_chain[i + 1]

562

563

# Verify issuer name matches subject

564

if cert.issuer != issuer_cert.subject:

565

return False, f"Issuer name mismatch at position {i}"

566

567

# Verify signature

568

try:

569

issuer_public_key = issuer_cert.public_key()

570

issuer_public_key.verify(

571

cert.signature,

572

cert.tbs_certificate_bytes,

573

padding.PKCS1v15(),

574

cert.signature_hash_algorithm

575

)

576

except Exception as e:

577

return False, f"Signature verification failed at position {i}: {e}"

578

579

return True, "Chain verification successful"

580

581

# Usage

582

with open('cert_chain.pem', 'rb') as f:

583

chain_data = f.read()

584

585

cert_chain = x509.load_pem_x509_certificates(chain_data)

586

valid, message = verify_certificate_chain(cert_chain)

587

print(f"Chain valid: {valid}, Message: {message}")

588

```

589

590

## OID Constants

591

592

Common object identifiers for names and extensions:

593

594

```python { .api }

595

class NameOID:

596

COMMON_NAME: ObjectIdentifier

597

COUNTRY_NAME: ObjectIdentifier

598

LOCALITY_NAME: ObjectIdentifier

599

STATE_OR_PROVINCE_NAME: ObjectIdentifier

600

ORGANIZATION_NAME: ObjectIdentifier

601

ORGANIZATIONAL_UNIT_NAME: ObjectIdentifier

602

EMAIL_ADDRESS: ObjectIdentifier

603

604

class ExtensionOID:

605

BASIC_CONSTRAINTS: ObjectIdentifier

606

KEY_USAGE: ObjectIdentifier

607

EXTENDED_KEY_USAGE: ObjectIdentifier

608

SUBJECT_ALTERNATIVE_NAME: ObjectIdentifier

609

ISSUER_ALTERNATIVE_NAME: ObjectIdentifier

610

SUBJECT_KEY_IDENTIFIER: ObjectIdentifier

611

AUTHORITY_KEY_IDENTIFIER: ObjectIdentifier

612

CRL_DISTRIBUTION_POINTS: ObjectIdentifier

613

AUTHORITY_INFORMATION_ACCESS: ObjectIdentifier

614

CERTIFICATE_POLICIES: ObjectIdentifier

615

616

class SignatureAlgorithmOID:

617

RSA_WITH_SHA256: ObjectIdentifier

618

RSA_WITH_SHA384: ObjectIdentifier

619

RSA_WITH_SHA512: ObjectIdentifier

620

ECDSA_WITH_SHA256: ObjectIdentifier

621

ECDSA_WITH_SHA384: ObjectIdentifier

622

ECDSA_WITH_SHA512: ObjectIdentifier

623

```

624

625

## Exception Handling

626

627

```python { .api }

628

class InvalidVersion(ValueError):

629

"""Invalid certificate version"""

630

631

class ExtensionNotFound(ValueError):

632

"""Certificate extension not found"""

633

634

class DuplicateExtension(ValueError):

635

"""Duplicate extension in certificate"""

636

637

class UnsupportedGeneralNameType(ValueError):

638

"""Unsupported general name type"""

639

```