Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/cryptography/x509/base.py: 25%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

335 statements  

1# This file is dual licensed under the terms of the Apache License, Version 

2# 2.0, and the BSD License. See the LICENSE file in the root of this repository 

3# for complete details. 

4 

5from __future__ import annotations 

6 

7import datetime 

8import os 

9import typing 

10from collections.abc import Iterable 

11 

12from cryptography import utils 

13from cryptography.hazmat.bindings._rust import x509 as rust_x509 

14from cryptography.hazmat.primitives import hashes 

15from cryptography.hazmat.primitives.asymmetric import ( 

16 dsa, 

17 ec, 

18 ed448, 

19 ed25519, 

20 mldsa, 

21 mlkem, 

22 padding, 

23 rsa, 

24 x448, 

25 x25519, 

26) 

27from cryptography.hazmat.primitives.asymmetric.types import ( 

28 CertificateIssuerPrivateKeyTypes, 

29 CertificatePublicKeyTypes, 

30) 

31from cryptography.x509.extensions import ( 

32 Extension, 

33 ExtensionType, 

34 _make_sequence_methods, 

35) 

36from cryptography.x509.name import Name, _ASN1Type 

37from cryptography.x509.oid import ObjectIdentifier 

38 

39_EARLIEST_UTC_TIME = datetime.datetime(1950, 1, 1) 

40 

41# This must be kept in sync with sign.rs's list of allowable types in 

42# identify_hash_type 

43_AllowedHashTypes = typing.Union[ 

44 hashes.SHA224, 

45 hashes.SHA256, 

46 hashes.SHA384, 

47 hashes.SHA512, 

48 hashes.SHA3_224, 

49 hashes.SHA3_256, 

50 hashes.SHA3_384, 

51 hashes.SHA3_512, 

52] 

53 

54 

55class AttributeNotFound(Exception): 

56 def __init__(self, msg: str, oid: ObjectIdentifier) -> None: 

57 super().__init__(msg) 

58 self.oid = oid 

59 

60 

61def _reject_duplicate_extension( 

62 extension: Extension[ExtensionType], 

63 extensions: list[Extension[ExtensionType]], 

64) -> None: 

65 # This is quadratic in the number of extensions 

66 for e in extensions: 

67 if e.oid == extension.oid: 

68 raise ValueError("This extension has already been set.") 

69 

70 

71def _reject_duplicate_attribute( 

72 oid: ObjectIdentifier, 

73 attributes: list[tuple[ObjectIdentifier, bytes, int | None]], 

74) -> None: 

75 # This is quadratic in the number of attributes 

76 for attr_oid, _, _ in attributes: 

77 if attr_oid == oid: 

78 raise ValueError("This attribute has already been set.") 

79 

80 

81def _convert_to_naive_utc_time(time: datetime.datetime) -> datetime.datetime: 

82 """Normalizes a datetime to a naive datetime in UTC. 

83 

84 time -- datetime to normalize. Assumed to be in UTC if not timezone 

85 aware. 

86 """ 

87 if time.tzinfo is not None: 

88 offset = time.utcoffset() 

89 offset = offset if offset else datetime.timedelta() 

90 return time.replace(tzinfo=None) - offset 

91 else: 

92 return time 

93 

94 

95class Attribute: 

96 def __init__( 

97 self, 

98 oid: ObjectIdentifier, 

99 value: bytes, 

100 _type: int = _ASN1Type.UTF8String.value, 

101 ) -> None: 

102 self._oid = oid 

103 self._value = value 

104 self._type = _type 

105 

106 @property 

107 def oid(self) -> ObjectIdentifier: 

108 return self._oid 

109 

110 @property 

111 def value(self) -> bytes: 

112 return self._value 

113 

114 def __repr__(self) -> str: 

115 return f"<Attribute(oid={self.oid}, value={self.value!r})>" 

116 

117 def __eq__(self, other: object) -> bool: 

118 if not isinstance(other, Attribute): 

119 return NotImplemented 

120 

121 return ( 

122 self.oid == other.oid 

123 and self.value == other.value 

124 and self._type == other._type 

125 ) 

126 

127 def __hash__(self) -> int: 

128 return hash((self.oid, self.value, self._type)) 

129 

130 

131class Attributes: 

132 def __init__( 

133 self, 

134 attributes: Iterable[Attribute], 

135 ) -> None: 

136 self._attributes = list(attributes) 

137 

138 __len__, __iter__, __getitem__ = _make_sequence_methods("_attributes") 

139 

140 def __repr__(self) -> str: 

141 return f"<Attributes({self._attributes})>" 

142 

143 def get_attribute_for_oid(self, oid: ObjectIdentifier) -> Attribute: 

144 for attr in self: 

145 if attr.oid == oid: 

146 return attr 

147 

148 raise AttributeNotFound(f"No {oid} attribute was found", oid) 

149 

150 

151class Version(utils.Enum): 

152 v1 = 0 

153 v3 = 2 

154 

155 

156class InvalidVersion(Exception): 

157 def __init__(self, msg: str, parsed_version: int) -> None: 

158 super().__init__(msg) 

159 self.parsed_version = parsed_version 

160 

161 

162Certificate = rust_x509.Certificate 

163RevokedCertificate = rust_x509.RevokedCertificate 

164 

165 

166CertificateRevocationList = rust_x509.CertificateRevocationList 

167CertificateSigningRequest = rust_x509.CertificateSigningRequest 

168 

169 

170load_pem_x509_certificate = rust_x509.load_pem_x509_certificate 

171load_der_x509_certificate = rust_x509.load_der_x509_certificate 

172 

173load_pem_x509_certificates = rust_x509.load_pem_x509_certificates 

174 

175load_pem_x509_csr = rust_x509.load_pem_x509_csr 

176load_der_x509_csr = rust_x509.load_der_x509_csr 

177 

178load_pem_x509_crl = rust_x509.load_pem_x509_crl 

179load_der_x509_crl = rust_x509.load_der_x509_crl 

180 

181 

182class CertificateSigningRequestBuilder: 

183 def __init__( 

184 self, 

185 subject_name: Name | None = None, 

186 extensions: list[Extension[ExtensionType]] = [], 

187 attributes: list[tuple[ObjectIdentifier, bytes, int | None]] = [], 

188 ): 

189 """ 

190 Creates an empty X.509 certificate request (v1). 

191 """ 

192 self._subject_name = subject_name 

193 self._extensions = extensions 

194 self._attributes = attributes 

195 

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

197 """ 

198 Sets the certificate requestor's distinguished name. 

199 """ 

200 if not isinstance(name, Name): 

201 raise TypeError("Expecting x509.Name object.") 

202 if self._subject_name is not None: 

203 raise ValueError("The subject name may only be set once.") 

204 return CertificateSigningRequestBuilder( 

205 name, self._extensions, self._attributes 

206 ) 

207 

208 def add_extension( 

209 self, extval: ExtensionType, critical: bool 

210 ) -> CertificateSigningRequestBuilder: 

211 """ 

212 Adds an X.509 extension to the certificate request. 

213 """ 

214 if not isinstance(extval, ExtensionType): 

215 raise TypeError("extension must be an ExtensionType") 

216 

217 extension = Extension(extval.oid, critical, extval) 

218 _reject_duplicate_extension(extension, self._extensions) 

219 

220 return CertificateSigningRequestBuilder( 

221 self._subject_name, 

222 [*self._extensions, extension], 

223 self._attributes, 

224 ) 

225 

226 def add_attribute( 

227 self, 

228 oid: ObjectIdentifier, 

229 value: bytes, 

230 *, 

231 _tag: _ASN1Type | None = None, 

232 ) -> CertificateSigningRequestBuilder: 

233 """ 

234 Adds an X.509 attribute with an OID and associated value. 

235 """ 

236 if not isinstance(oid, ObjectIdentifier): 

237 raise TypeError("oid must be an ObjectIdentifier") 

238 

239 if not isinstance(value, bytes): 

240 raise TypeError("value must be bytes") 

241 

242 if _tag is not None and not isinstance(_tag, _ASN1Type): 

243 raise TypeError("tag must be _ASN1Type") 

244 

245 _reject_duplicate_attribute(oid, self._attributes) 

246 

247 if _tag is not None: 

248 tag = _tag.value 

249 else: 

250 tag = None 

251 

252 return CertificateSigningRequestBuilder( 

253 self._subject_name, 

254 self._extensions, 

255 [*self._attributes, (oid, value, tag)], 

256 ) 

257 

258 def sign( 

259 self, 

260 private_key: CertificateIssuerPrivateKeyTypes, 

261 algorithm: _AllowedHashTypes | None, 

262 backend: typing.Any = None, 

263 *, 

264 rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, 

265 ecdsa_deterministic: bool | None = None, 

266 ) -> CertificateSigningRequest: 

267 """ 

268 Signs the request using the requestor's private key. 

269 """ 

270 if self._subject_name is None: 

271 raise ValueError("A CertificateSigningRequest must have a subject") 

272 

273 if rsa_padding is not None: 

274 if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): 

275 raise TypeError("Padding must be PSS or PKCS1v15") 

276 if not isinstance(private_key, rsa.RSAPrivateKey): 

277 raise TypeError("Padding is only supported for RSA keys") 

278 

279 if ecdsa_deterministic is not None: 

280 if not isinstance(private_key, ec.EllipticCurvePrivateKey): 

281 raise TypeError( 

282 "Deterministic ECDSA is only supported for EC keys" 

283 ) 

284 

285 return rust_x509.create_x509_csr( 

286 self, 

287 private_key, 

288 algorithm, 

289 rsa_padding, 

290 ecdsa_deterministic, 

291 ) 

292 

293 

294class CertificateBuilder: 

295 _extensions: list[Extension[ExtensionType]] 

296 

297 def __init__( 

298 self, 

299 issuer_name: Name | None = None, 

300 subject_name: Name | None = None, 

301 public_key: CertificatePublicKeyTypes | None = None, 

302 serial_number: int | None = None, 

303 not_valid_before: datetime.datetime | None = None, 

304 not_valid_after: datetime.datetime | None = None, 

305 extensions: list[Extension[ExtensionType]] = [], 

306 public_key_rsa_padding: type[padding.PSS] | None = None, 

307 ) -> None: 

308 self._version = Version.v3 

309 self._issuer_name = issuer_name 

310 self._subject_name = subject_name 

311 self._public_key = public_key 

312 self._serial_number = serial_number 

313 self._not_valid_before = not_valid_before 

314 self._not_valid_after = not_valid_after 

315 self._extensions = extensions 

316 self._public_key_rsa_padding = public_key_rsa_padding 

317 

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

319 """ 

320 Sets the CA's distinguished name. 

321 """ 

322 if not isinstance(name, Name): 

323 raise TypeError("Expecting x509.Name object.") 

324 if self._issuer_name is not None: 

325 raise ValueError("The issuer name may only be set once.") 

326 return CertificateBuilder( 

327 name, 

328 self._subject_name, 

329 self._public_key, 

330 self._serial_number, 

331 self._not_valid_before, 

332 self._not_valid_after, 

333 self._extensions, 

334 self._public_key_rsa_padding, 

335 ) 

336 

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

338 """ 

339 Sets the requestor's distinguished name. 

340 """ 

341 if not isinstance(name, Name): 

342 raise TypeError("Expecting x509.Name object.") 

343 if self._subject_name is not None: 

344 raise ValueError("The subject name may only be set once.") 

345 return CertificateBuilder( 

346 self._issuer_name, 

347 name, 

348 self._public_key, 

349 self._serial_number, 

350 self._not_valid_before, 

351 self._not_valid_after, 

352 self._extensions, 

353 self._public_key_rsa_padding, 

354 ) 

355 

356 def public_key( 

357 self, 

358 key: CertificatePublicKeyTypes, 

359 *, 

360 rsa_padding: type[padding.PSS] | None = None, 

361 ) -> CertificateBuilder: 

362 """ 

363 Sets the requestor's public key (as found in the signing request). 

364 """ 

365 if not isinstance( 

366 key, 

367 ( 

368 dsa.DSAPublicKey, 

369 rsa.RSAPublicKey, 

370 ec.EllipticCurvePublicKey, 

371 ed25519.Ed25519PublicKey, 

372 ed448.Ed448PublicKey, 

373 mldsa.MLDSA44PublicKey, 

374 mldsa.MLDSA65PublicKey, 

375 mldsa.MLDSA87PublicKey, 

376 mlkem.MLKEM768PublicKey, 

377 mlkem.MLKEM1024PublicKey, 

378 x25519.X25519PublicKey, 

379 x448.X448PublicKey, 

380 ), 

381 ): 

382 raise TypeError( 

383 "Expecting one of DSAPublicKey, RSAPublicKey," 

384 " EllipticCurvePublicKey, Ed25519PublicKey," 

385 " Ed448PublicKey, MLDSA44PublicKey, MLDSA65PublicKey," 

386 " MLDSA87PublicKey, MLKEM768PublicKey, MLKEM1024PublicKey," 

387 " X25519PublicKey or X448PublicKey." 

388 ) 

389 if rsa_padding is not None: 

390 if rsa_padding is not padding.PSS: 

391 raise TypeError( 

392 "rsa_padding must be the PSS class, not an instance" 

393 ) 

394 if not isinstance(key, rsa.RSAPublicKey): 

395 raise TypeError( 

396 "rsa_padding is only supported with RSA public keys" 

397 ) 

398 if self._public_key is not None: 

399 raise ValueError("The public key may only be set once.") 

400 return CertificateBuilder( 

401 self._issuer_name, 

402 self._subject_name, 

403 key, 

404 self._serial_number, 

405 self._not_valid_before, 

406 self._not_valid_after, 

407 self._extensions, 

408 rsa_padding, 

409 ) 

410 

411 def serial_number(self, number: int) -> CertificateBuilder: 

412 """ 

413 Sets the certificate serial number. 

414 """ 

415 if not isinstance(number, int): 

416 raise TypeError("Serial number must be of integral type.") 

417 if self._serial_number is not None: 

418 raise ValueError("The serial number may only be set once.") 

419 if number <= 0: 

420 raise ValueError("The serial number should be positive.") 

421 

422 # ASN.1 integers are always signed, so most significant bit must be 

423 # zero. 

424 if number.bit_length() >= 160: # As defined in RFC 5280 

425 raise ValueError( 

426 "The serial number should not be more than 159 bits." 

427 ) 

428 return CertificateBuilder( 

429 self._issuer_name, 

430 self._subject_name, 

431 self._public_key, 

432 number, 

433 self._not_valid_before, 

434 self._not_valid_after, 

435 self._extensions, 

436 self._public_key_rsa_padding, 

437 ) 

438 

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

440 """ 

441 Sets the certificate activation time. 

442 """ 

443 if not isinstance(time, datetime.datetime): 

444 raise TypeError("Expecting datetime object.") 

445 if self._not_valid_before is not None: 

446 raise ValueError("The not valid before may only be set once.") 

447 time = _convert_to_naive_utc_time(time) 

448 if time < _EARLIEST_UTC_TIME: 

449 raise ValueError( 

450 "The not valid before date must be on or after" 

451 " 1950 January 1)." 

452 ) 

453 if self._not_valid_after is not None and time > self._not_valid_after: 

454 raise ValueError( 

455 "The not valid before date must be before the not valid after " 

456 "date." 

457 ) 

458 return CertificateBuilder( 

459 self._issuer_name, 

460 self._subject_name, 

461 self._public_key, 

462 self._serial_number, 

463 time, 

464 self._not_valid_after, 

465 self._extensions, 

466 self._public_key_rsa_padding, 

467 ) 

468 

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

470 """ 

471 Sets the certificate expiration time. 

472 """ 

473 if not isinstance(time, datetime.datetime): 

474 raise TypeError("Expecting datetime object.") 

475 if self._not_valid_after is not None: 

476 raise ValueError("The not valid after may only be set once.") 

477 time = _convert_to_naive_utc_time(time) 

478 if time < _EARLIEST_UTC_TIME: 

479 raise ValueError( 

480 "The not valid after date must be on or after 1950 January 1." 

481 ) 

482 if ( 

483 self._not_valid_before is not None 

484 and time < self._not_valid_before 

485 ): 

486 raise ValueError( 

487 "The not valid after date must be after the not valid before " 

488 "date." 

489 ) 

490 return CertificateBuilder( 

491 self._issuer_name, 

492 self._subject_name, 

493 self._public_key, 

494 self._serial_number, 

495 self._not_valid_before, 

496 time, 

497 self._extensions, 

498 self._public_key_rsa_padding, 

499 ) 

500 

501 def add_extension( 

502 self, extval: ExtensionType, critical: bool 

503 ) -> CertificateBuilder: 

504 """ 

505 Adds an X.509 extension to the certificate. 

506 """ 

507 if not isinstance(extval, ExtensionType): 

508 raise TypeError("extension must be an ExtensionType") 

509 

510 extension = Extension(extval.oid, critical, extval) 

511 _reject_duplicate_extension(extension, self._extensions) 

512 

513 return CertificateBuilder( 

514 self._issuer_name, 

515 self._subject_name, 

516 self._public_key, 

517 self._serial_number, 

518 self._not_valid_before, 

519 self._not_valid_after, 

520 [*self._extensions, extension], 

521 self._public_key_rsa_padding, 

522 ) 

523 

524 def sign( 

525 self, 

526 private_key: CertificateIssuerPrivateKeyTypes, 

527 algorithm: _AllowedHashTypes | None, 

528 backend: typing.Any = None, 

529 *, 

530 rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, 

531 ecdsa_deterministic: bool | None = None, 

532 ) -> Certificate: 

533 """ 

534 Signs the certificate using the CA's private key. 

535 """ 

536 if self._subject_name is None: 

537 raise ValueError("A certificate must have a subject name") 

538 

539 if self._issuer_name is None: 

540 raise ValueError("A certificate must have an issuer name") 

541 

542 if self._serial_number is None: 

543 raise ValueError("A certificate must have a serial number") 

544 

545 if self._not_valid_before is None: 

546 raise ValueError("A certificate must have a not valid before time") 

547 

548 if self._not_valid_after is None: 

549 raise ValueError("A certificate must have a not valid after time") 

550 

551 if self._public_key is None: 

552 raise ValueError("A certificate must have a public key") 

553 

554 if private_key is None: 

555 raise TypeError("Need private key to sign certificate") 

556 

557 if rsa_padding is not None: 

558 if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): 

559 raise TypeError("Padding must be PSS or PKCS1v15") 

560 if not isinstance(private_key, rsa.RSAPrivateKey): 

561 raise TypeError("Padding is only supported for RSA keys") 

562 

563 if ecdsa_deterministic is not None: 

564 if not isinstance(private_key, ec.EllipticCurvePrivateKey): 

565 raise TypeError( 

566 "Deterministic ECDSA is only supported for EC keys" 

567 ) 

568 

569 return rust_x509.create_x509_certificate( 

570 self, 

571 private_key, 

572 algorithm, 

573 rsa_padding, 

574 ecdsa_deterministic, 

575 ) 

576 

577 def create_unsigned(self) -> Certificate: 

578 """ 

579 Creates an unsigned certificate, per RFC 9925. 

580 """ 

581 if self._subject_name is None: 

582 raise ValueError("A certificate must have a subject name") 

583 

584 if self._issuer_name is None: 

585 raise ValueError("A certificate must have an issuer name") 

586 

587 if self._serial_number is None: 

588 raise ValueError("A certificate must have a serial number") 

589 

590 if self._not_valid_before is None: 

591 raise ValueError("A certificate must have a not valid before time") 

592 

593 if self._not_valid_after is None: 

594 raise ValueError("A certificate must have a not valid after time") 

595 

596 if self._public_key is None: 

597 raise ValueError("A certificate must have a public key") 

598 

599 return rust_x509.create_x509_certificate( 

600 self, 

601 private_key=None, 

602 hash_algorithm=None, 

603 rsa_padding=None, 

604 ecdsa_deterministic=None, 

605 ) 

606 

607 

608class CertificateRevocationListBuilder: 

609 _extensions: list[Extension[ExtensionType]] 

610 _revoked_certificates: list[RevokedCertificate] 

611 

612 def __init__( 

613 self, 

614 issuer_name: Name | None = None, 

615 last_update: datetime.datetime | None = None, 

616 next_update: datetime.datetime | None = None, 

617 extensions: list[Extension[ExtensionType]] = [], 

618 revoked_certificates: list[RevokedCertificate] = [], 

619 ): 

620 self._issuer_name = issuer_name 

621 self._last_update = last_update 

622 self._next_update = next_update 

623 self._extensions = extensions 

624 self._revoked_certificates = revoked_certificates 

625 

626 def issuer_name( 

627 self, issuer_name: Name 

628 ) -> CertificateRevocationListBuilder: 

629 if not isinstance(issuer_name, Name): 

630 raise TypeError("Expecting x509.Name object.") 

631 if self._issuer_name is not None: 

632 raise ValueError("The issuer name may only be set once.") 

633 return CertificateRevocationListBuilder( 

634 issuer_name, 

635 self._last_update, 

636 self._next_update, 

637 self._extensions, 

638 self._revoked_certificates, 

639 ) 

640 

641 def last_update( 

642 self, last_update: datetime.datetime 

643 ) -> CertificateRevocationListBuilder: 

644 if not isinstance(last_update, datetime.datetime): 

645 raise TypeError("Expecting datetime object.") 

646 if self._last_update is not None: 

647 raise ValueError("Last update may only be set once.") 

648 last_update = _convert_to_naive_utc_time(last_update) 

649 if last_update < _EARLIEST_UTC_TIME: 

650 raise ValueError( 

651 "The last update date must be on or after 1950 January 1." 

652 ) 

653 if self._next_update is not None and last_update > self._next_update: 

654 raise ValueError( 

655 "The last update date must be before the next update date." 

656 ) 

657 return CertificateRevocationListBuilder( 

658 self._issuer_name, 

659 last_update, 

660 self._next_update, 

661 self._extensions, 

662 self._revoked_certificates, 

663 ) 

664 

665 def next_update( 

666 self, next_update: datetime.datetime 

667 ) -> CertificateRevocationListBuilder: 

668 if not isinstance(next_update, datetime.datetime): 

669 raise TypeError("Expecting datetime object.") 

670 if self._next_update is not None: 

671 raise ValueError("Last update may only be set once.") 

672 next_update = _convert_to_naive_utc_time(next_update) 

673 if next_update < _EARLIEST_UTC_TIME: 

674 raise ValueError( 

675 "The last update date must be on or after 1950 January 1." 

676 ) 

677 if self._last_update is not None and next_update < self._last_update: 

678 raise ValueError( 

679 "The next update date must be after the last update date." 

680 ) 

681 return CertificateRevocationListBuilder( 

682 self._issuer_name, 

683 self._last_update, 

684 next_update, 

685 self._extensions, 

686 self._revoked_certificates, 

687 ) 

688 

689 def add_extension( 

690 self, extval: ExtensionType, critical: bool 

691 ) -> CertificateRevocationListBuilder: 

692 """ 

693 Adds an X.509 extension to the certificate revocation list. 

694 """ 

695 if not isinstance(extval, ExtensionType): 

696 raise TypeError("extension must be an ExtensionType") 

697 

698 extension = Extension(extval.oid, critical, extval) 

699 _reject_duplicate_extension(extension, self._extensions) 

700 return CertificateRevocationListBuilder( 

701 self._issuer_name, 

702 self._last_update, 

703 self._next_update, 

704 [*self._extensions, extension], 

705 self._revoked_certificates, 

706 ) 

707 

708 def add_revoked_certificate( 

709 self, revoked_certificate: RevokedCertificate 

710 ) -> CertificateRevocationListBuilder: 

711 """ 

712 Adds a revoked certificate to the CRL. 

713 """ 

714 if not isinstance(revoked_certificate, RevokedCertificate): 

715 raise TypeError("Must be an instance of RevokedCertificate") 

716 

717 return CertificateRevocationListBuilder( 

718 self._issuer_name, 

719 self._last_update, 

720 self._next_update, 

721 self._extensions, 

722 [*self._revoked_certificates, revoked_certificate], 

723 ) 

724 

725 def sign( 

726 self, 

727 private_key: CertificateIssuerPrivateKeyTypes, 

728 algorithm: _AllowedHashTypes | None, 

729 backend: typing.Any = None, 

730 *, 

731 rsa_padding: padding.PSS | padding.PKCS1v15 | None = None, 

732 ecdsa_deterministic: bool | None = None, 

733 ) -> CertificateRevocationList: 

734 if self._issuer_name is None: 

735 raise ValueError("A CRL must have an issuer name") 

736 

737 if self._last_update is None: 

738 raise ValueError("A CRL must have a last update time") 

739 

740 if self._next_update is None: 

741 raise ValueError("A CRL must have a next update time") 

742 

743 if rsa_padding is not None: 

744 if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)): 

745 raise TypeError("Padding must be PSS or PKCS1v15") 

746 if not isinstance(private_key, rsa.RSAPrivateKey): 

747 raise TypeError("Padding is only supported for RSA keys") 

748 

749 if ecdsa_deterministic is not None: 

750 if not isinstance(private_key, ec.EllipticCurvePrivateKey): 

751 raise TypeError( 

752 "Deterministic ECDSA is only supported for EC keys" 

753 ) 

754 

755 return rust_x509.create_x509_crl( 

756 self, 

757 private_key, 

758 algorithm, 

759 rsa_padding, 

760 ecdsa_deterministic, 

761 ) 

762 

763 

764class RevokedCertificateBuilder: 

765 def __init__( 

766 self, 

767 serial_number: int | None = None, 

768 revocation_date: datetime.datetime | None = None, 

769 extensions: list[Extension[ExtensionType]] = [], 

770 ): 

771 self._serial_number = serial_number 

772 self._revocation_date = revocation_date 

773 self._extensions = extensions 

774 

775 def serial_number(self, number: int) -> RevokedCertificateBuilder: 

776 if not isinstance(number, int): 

777 raise TypeError("Serial number must be of integral type.") 

778 if self._serial_number is not None: 

779 raise ValueError("The serial number may only be set once.") 

780 if number <= 0: 

781 raise ValueError("The serial number should be positive") 

782 

783 # ASN.1 integers are always signed, so most significant bit must be 

784 # zero. 

785 if number.bit_length() >= 160: # As defined in RFC 5280 

786 raise ValueError( 

787 "The serial number should not be more than 159 bits." 

788 ) 

789 return RevokedCertificateBuilder( 

790 number, self._revocation_date, self._extensions 

791 ) 

792 

793 def revocation_date( 

794 self, time: datetime.datetime 

795 ) -> RevokedCertificateBuilder: 

796 if not isinstance(time, datetime.datetime): 

797 raise TypeError("Expecting datetime object.") 

798 if self._revocation_date is not None: 

799 raise ValueError("The revocation date may only be set once.") 

800 time = _convert_to_naive_utc_time(time) 

801 if time < _EARLIEST_UTC_TIME: 

802 raise ValueError( 

803 "The revocation date must be on or after 1950 January 1." 

804 ) 

805 return RevokedCertificateBuilder( 

806 self._serial_number, time, self._extensions 

807 ) 

808 

809 def add_extension( 

810 self, extval: ExtensionType, critical: bool 

811 ) -> RevokedCertificateBuilder: 

812 if not isinstance(extval, ExtensionType): 

813 raise TypeError("extension must be an ExtensionType") 

814 

815 extension = Extension(extval.oid, critical, extval) 

816 _reject_duplicate_extension(extension, self._extensions) 

817 return RevokedCertificateBuilder( 

818 self._serial_number, 

819 self._revocation_date, 

820 [*self._extensions, extension], 

821 ) 

822 

823 def build(self, backend: typing.Any = None) -> RevokedCertificate: 

824 if self._serial_number is None: 

825 raise ValueError("A revoked certificate must have a serial number") 

826 if self._revocation_date is None: 

827 raise ValueError( 

828 "A revoked certificate must have a revocation date" 

829 ) 

830 return rust_x509.create_revoked_certificate(self) 

831 

832 

833def random_serial_number() -> int: 

834 return int.from_bytes(os.urandom(20), "big") >> 1