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

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

319 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 padding, 

22 rsa, 

23 x448, 

24 x25519, 

25) 

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

27 CertificateIssuerPrivateKeyTypes, 

28 CertificatePublicKeyTypes, 

29) 

30from cryptography.x509.extensions import ( 

31 Extension, 

32 ExtensionType, 

33 _make_sequence_methods, 

34) 

35from cryptography.x509.name import Name, _ASN1Type 

36from cryptography.x509.oid import ObjectIdentifier 

37 

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

39 

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

41# identify_hash_type 

42_AllowedHashTypes = typing.Union[ 

43 hashes.SHA224, 

44 hashes.SHA256, 

45 hashes.SHA384, 

46 hashes.SHA512, 

47 hashes.SHA3_224, 

48 hashes.SHA3_256, 

49 hashes.SHA3_384, 

50 hashes.SHA3_512, 

51] 

52 

53 

54class AttributeNotFound(Exception): 

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

56 super().__init__(msg) 

57 self.oid = oid 

58 

59 

60def _reject_duplicate_extension( 

61 extension: Extension[ExtensionType], 

62 extensions: list[Extension[ExtensionType]], 

63) -> None: 

64 # This is quadratic in the number of extensions 

65 for e in extensions: 

66 if e.oid == extension.oid: 

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

68 

69 

70def _reject_duplicate_attribute( 

71 oid: ObjectIdentifier, 

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

73) -> None: 

74 # This is quadratic in the number of attributes 

75 for attr_oid, _, _ in attributes: 

76 if attr_oid == oid: 

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

78 

79 

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

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

82 

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

84 aware. 

85 """ 

86 if time.tzinfo is not None: 

87 offset = time.utcoffset() 

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

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

90 else: 

91 return time 

92 

93 

94class Attribute: 

95 def __init__( 

96 self, 

97 oid: ObjectIdentifier, 

98 value: bytes, 

99 _type: int = _ASN1Type.UTF8String.value, 

100 ) -> None: 

101 self._oid = oid 

102 self._value = value 

103 self._type = _type 

104 

105 @property 

106 def oid(self) -> ObjectIdentifier: 

107 return self._oid 

108 

109 @property 

110 def value(self) -> bytes: 

111 return self._value 

112 

113 def __repr__(self) -> str: 

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

115 

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

117 if not isinstance(other, Attribute): 

118 return NotImplemented 

119 

120 return ( 

121 self.oid == other.oid 

122 and self.value == other.value 

123 and self._type == other._type 

124 ) 

125 

126 def __hash__(self) -> int: 

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

128 

129 

130class Attributes: 

131 def __init__( 

132 self, 

133 attributes: Iterable[Attribute], 

134 ) -> None: 

135 self._attributes = list(attributes) 

136 

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

138 

139 def __repr__(self) -> str: 

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

141 

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

143 for attr in self: 

144 if attr.oid == oid: 

145 return attr 

146 

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

148 

149 

150class Version(utils.Enum): 

151 v1 = 0 

152 v3 = 2 

153 

154 

155class InvalidVersion(Exception): 

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

157 super().__init__(msg) 

158 self.parsed_version = parsed_version 

159 

160 

161Certificate = rust_x509.Certificate 

162RevokedCertificate = rust_x509.RevokedCertificate 

163 

164 

165CertificateRevocationList = rust_x509.CertificateRevocationList 

166CertificateSigningRequest = rust_x509.CertificateSigningRequest 

167 

168 

169load_pem_x509_certificate = rust_x509.load_pem_x509_certificate 

170load_der_x509_certificate = rust_x509.load_der_x509_certificate 

171 

172load_pem_x509_certificates = rust_x509.load_pem_x509_certificates 

173 

174load_pem_x509_csr = rust_x509.load_pem_x509_csr 

175load_der_x509_csr = rust_x509.load_der_x509_csr 

176 

177load_pem_x509_crl = rust_x509.load_pem_x509_crl 

178load_der_x509_crl = rust_x509.load_der_x509_crl 

179 

180 

181class CertificateSigningRequestBuilder: 

182 def __init__( 

183 self, 

184 subject_name: Name | None = None, 

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

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

187 ): 

188 """ 

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

190 """ 

191 self._subject_name = subject_name 

192 self._extensions = extensions 

193 self._attributes = attributes 

194 

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

196 """ 

197 Sets the certificate requestor's distinguished name. 

198 """ 

199 if not isinstance(name, Name): 

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

201 if self._subject_name is not None: 

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

203 return CertificateSigningRequestBuilder( 

204 name, self._extensions, self._attributes 

205 ) 

206 

207 def add_extension( 

208 self, extval: ExtensionType, critical: bool 

209 ) -> CertificateSigningRequestBuilder: 

210 """ 

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

212 """ 

213 if not isinstance(extval, ExtensionType): 

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

215 

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

217 _reject_duplicate_extension(extension, self._extensions) 

218 

219 return CertificateSigningRequestBuilder( 

220 self._subject_name, 

221 [*self._extensions, extension], 

222 self._attributes, 

223 ) 

224 

225 def add_attribute( 

226 self, 

227 oid: ObjectIdentifier, 

228 value: bytes, 

229 *, 

230 _tag: _ASN1Type | None = None, 

231 ) -> CertificateSigningRequestBuilder: 

232 """ 

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

234 """ 

235 if not isinstance(oid, ObjectIdentifier): 

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

237 

238 if not isinstance(value, bytes): 

239 raise TypeError("value must be bytes") 

240 

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

242 raise TypeError("tag must be _ASN1Type") 

243 

244 _reject_duplicate_attribute(oid, self._attributes) 

245 

246 if _tag is not None: 

247 tag = _tag.value 

248 else: 

249 tag = None 

250 

251 return CertificateSigningRequestBuilder( 

252 self._subject_name, 

253 self._extensions, 

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

255 ) 

256 

257 def sign( 

258 self, 

259 private_key: CertificateIssuerPrivateKeyTypes, 

260 algorithm: _AllowedHashTypes | None, 

261 backend: typing.Any = None, 

262 *, 

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

264 ecdsa_deterministic: bool | None = None, 

265 ) -> CertificateSigningRequest: 

266 """ 

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

268 """ 

269 if self._subject_name is None: 

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

271 

272 if rsa_padding is not None: 

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

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

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

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

277 

278 if ecdsa_deterministic is not None: 

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

280 raise TypeError( 

281 "Deterministic ECDSA is only supported for EC keys" 

282 ) 

283 

284 return rust_x509.create_x509_csr( 

285 self, 

286 private_key, 

287 algorithm, 

288 rsa_padding, 

289 ecdsa_deterministic, 

290 ) 

291 

292 

293class CertificateBuilder: 

294 _extensions: list[Extension[ExtensionType]] 

295 

296 def __init__( 

297 self, 

298 issuer_name: Name | None = None, 

299 subject_name: Name | None = None, 

300 public_key: CertificatePublicKeyTypes | None = None, 

301 serial_number: int | None = None, 

302 not_valid_before: datetime.datetime | None = None, 

303 not_valid_after: datetime.datetime | None = None, 

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

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

306 ) -> None: 

307 self._version = Version.v3 

308 self._issuer_name = issuer_name 

309 self._subject_name = subject_name 

310 self._public_key = public_key 

311 self._serial_number = serial_number 

312 self._not_valid_before = not_valid_before 

313 self._not_valid_after = not_valid_after 

314 self._extensions = extensions 

315 self._public_key_rsa_padding = public_key_rsa_padding 

316 

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

318 """ 

319 Sets the CA's distinguished name. 

320 """ 

321 if not isinstance(name, Name): 

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

323 if self._issuer_name is not None: 

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

325 return CertificateBuilder( 

326 name, 

327 self._subject_name, 

328 self._public_key, 

329 self._serial_number, 

330 self._not_valid_before, 

331 self._not_valid_after, 

332 self._extensions, 

333 self._public_key_rsa_padding, 

334 ) 

335 

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

337 """ 

338 Sets the requestor's distinguished name. 

339 """ 

340 if not isinstance(name, Name): 

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

342 if self._subject_name is not None: 

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

344 return CertificateBuilder( 

345 self._issuer_name, 

346 name, 

347 self._public_key, 

348 self._serial_number, 

349 self._not_valid_before, 

350 self._not_valid_after, 

351 self._extensions, 

352 self._public_key_rsa_padding, 

353 ) 

354 

355 def public_key( 

356 self, 

357 key: CertificatePublicKeyTypes, 

358 *, 

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

360 ) -> CertificateBuilder: 

361 """ 

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

363 """ 

364 if not isinstance( 

365 key, 

366 ( 

367 dsa.DSAPublicKey, 

368 rsa.RSAPublicKey, 

369 ec.EllipticCurvePublicKey, 

370 ed25519.Ed25519PublicKey, 

371 ed448.Ed448PublicKey, 

372 mldsa.MLDSA44PublicKey, 

373 mldsa.MLDSA65PublicKey, 

374 mldsa.MLDSA87PublicKey, 

375 x25519.X25519PublicKey, 

376 x448.X448PublicKey, 

377 ), 

378 ): 

379 raise TypeError( 

380 "Expecting one of DSAPublicKey, RSAPublicKey," 

381 " EllipticCurvePublicKey, Ed25519PublicKey," 

382 " Ed448PublicKey, MLDSA44PublicKey, MLDSA65PublicKey," 

383 " MLDSA87PublicKey, X25519PublicKey, or " 

384 "X448PublicKey." 

385 ) 

386 if rsa_padding is not None: 

387 if rsa_padding is not padding.PSS: 

388 raise TypeError( 

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

390 ) 

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

392 raise TypeError( 

393 "rsa_padding is only supported with RSA public keys" 

394 ) 

395 if self._public_key is not None: 

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

397 return CertificateBuilder( 

398 self._issuer_name, 

399 self._subject_name, 

400 key, 

401 self._serial_number, 

402 self._not_valid_before, 

403 self._not_valid_after, 

404 self._extensions, 

405 rsa_padding, 

406 ) 

407 

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

409 """ 

410 Sets the certificate serial number. 

411 """ 

412 if not isinstance(number, int): 

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

414 if self._serial_number is not None: 

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

416 if number <= 0: 

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

418 

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

420 # zero. 

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

422 raise ValueError( 

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

424 ) 

425 return CertificateBuilder( 

426 self._issuer_name, 

427 self._subject_name, 

428 self._public_key, 

429 number, 

430 self._not_valid_before, 

431 self._not_valid_after, 

432 self._extensions, 

433 self._public_key_rsa_padding, 

434 ) 

435 

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

437 """ 

438 Sets the certificate activation time. 

439 """ 

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

441 raise TypeError("Expecting datetime object.") 

442 if self._not_valid_before is not None: 

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

444 time = _convert_to_naive_utc_time(time) 

445 if time < _EARLIEST_UTC_TIME: 

446 raise ValueError( 

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

448 " 1950 January 1)." 

449 ) 

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

451 raise ValueError( 

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

453 "date." 

454 ) 

455 return CertificateBuilder( 

456 self._issuer_name, 

457 self._subject_name, 

458 self._public_key, 

459 self._serial_number, 

460 time, 

461 self._not_valid_after, 

462 self._extensions, 

463 self._public_key_rsa_padding, 

464 ) 

465 

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

467 """ 

468 Sets the certificate expiration time. 

469 """ 

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

471 raise TypeError("Expecting datetime object.") 

472 if self._not_valid_after is not None: 

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

474 time = _convert_to_naive_utc_time(time) 

475 if time < _EARLIEST_UTC_TIME: 

476 raise ValueError( 

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

478 ) 

479 if ( 

480 self._not_valid_before is not None 

481 and time < self._not_valid_before 

482 ): 

483 raise ValueError( 

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

485 "date." 

486 ) 

487 return CertificateBuilder( 

488 self._issuer_name, 

489 self._subject_name, 

490 self._public_key, 

491 self._serial_number, 

492 self._not_valid_before, 

493 time, 

494 self._extensions, 

495 self._public_key_rsa_padding, 

496 ) 

497 

498 def add_extension( 

499 self, extval: ExtensionType, critical: bool 

500 ) -> CertificateBuilder: 

501 """ 

502 Adds an X.509 extension to the certificate. 

503 """ 

504 if not isinstance(extval, ExtensionType): 

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

506 

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

508 _reject_duplicate_extension(extension, self._extensions) 

509 

510 return CertificateBuilder( 

511 self._issuer_name, 

512 self._subject_name, 

513 self._public_key, 

514 self._serial_number, 

515 self._not_valid_before, 

516 self._not_valid_after, 

517 [*self._extensions, extension], 

518 self._public_key_rsa_padding, 

519 ) 

520 

521 def sign( 

522 self, 

523 private_key: CertificateIssuerPrivateKeyTypes, 

524 algorithm: _AllowedHashTypes | None, 

525 backend: typing.Any = None, 

526 *, 

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

528 ecdsa_deterministic: bool | None = None, 

529 ) -> Certificate: 

530 """ 

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

532 """ 

533 if self._subject_name is None: 

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

535 

536 if self._issuer_name is None: 

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

538 

539 if self._serial_number is None: 

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

541 

542 if self._not_valid_before is None: 

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

544 

545 if self._not_valid_after is None: 

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

547 

548 if self._public_key is None: 

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

550 

551 if rsa_padding is not None: 

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

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

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

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

556 

557 if ecdsa_deterministic is not None: 

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

559 raise TypeError( 

560 "Deterministic ECDSA is only supported for EC keys" 

561 ) 

562 

563 return rust_x509.create_x509_certificate( 

564 self, 

565 private_key, 

566 algorithm, 

567 rsa_padding, 

568 ecdsa_deterministic, 

569 ) 

570 

571 

572class CertificateRevocationListBuilder: 

573 _extensions: list[Extension[ExtensionType]] 

574 _revoked_certificates: list[RevokedCertificate] 

575 

576 def __init__( 

577 self, 

578 issuer_name: Name | None = None, 

579 last_update: datetime.datetime | None = None, 

580 next_update: datetime.datetime | None = None, 

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

582 revoked_certificates: list[RevokedCertificate] = [], 

583 ): 

584 self._issuer_name = issuer_name 

585 self._last_update = last_update 

586 self._next_update = next_update 

587 self._extensions = extensions 

588 self._revoked_certificates = revoked_certificates 

589 

590 def issuer_name( 

591 self, issuer_name: Name 

592 ) -> CertificateRevocationListBuilder: 

593 if not isinstance(issuer_name, Name): 

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

595 if self._issuer_name is not None: 

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

597 return CertificateRevocationListBuilder( 

598 issuer_name, 

599 self._last_update, 

600 self._next_update, 

601 self._extensions, 

602 self._revoked_certificates, 

603 ) 

604 

605 def last_update( 

606 self, last_update: datetime.datetime 

607 ) -> CertificateRevocationListBuilder: 

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

609 raise TypeError("Expecting datetime object.") 

610 if self._last_update is not None: 

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

612 last_update = _convert_to_naive_utc_time(last_update) 

613 if last_update < _EARLIEST_UTC_TIME: 

614 raise ValueError( 

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

616 ) 

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

618 raise ValueError( 

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

620 ) 

621 return CertificateRevocationListBuilder( 

622 self._issuer_name, 

623 last_update, 

624 self._next_update, 

625 self._extensions, 

626 self._revoked_certificates, 

627 ) 

628 

629 def next_update( 

630 self, next_update: datetime.datetime 

631 ) -> CertificateRevocationListBuilder: 

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

633 raise TypeError("Expecting datetime object.") 

634 if self._next_update is not None: 

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

636 next_update = _convert_to_naive_utc_time(next_update) 

637 if next_update < _EARLIEST_UTC_TIME: 

638 raise ValueError( 

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

640 ) 

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

642 raise ValueError( 

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

644 ) 

645 return CertificateRevocationListBuilder( 

646 self._issuer_name, 

647 self._last_update, 

648 next_update, 

649 self._extensions, 

650 self._revoked_certificates, 

651 ) 

652 

653 def add_extension( 

654 self, extval: ExtensionType, critical: bool 

655 ) -> CertificateRevocationListBuilder: 

656 """ 

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

658 """ 

659 if not isinstance(extval, ExtensionType): 

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

661 

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

663 _reject_duplicate_extension(extension, self._extensions) 

664 return CertificateRevocationListBuilder( 

665 self._issuer_name, 

666 self._last_update, 

667 self._next_update, 

668 [*self._extensions, extension], 

669 self._revoked_certificates, 

670 ) 

671 

672 def add_revoked_certificate( 

673 self, revoked_certificate: RevokedCertificate 

674 ) -> CertificateRevocationListBuilder: 

675 """ 

676 Adds a revoked certificate to the CRL. 

677 """ 

678 if not isinstance(revoked_certificate, RevokedCertificate): 

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

680 

681 return CertificateRevocationListBuilder( 

682 self._issuer_name, 

683 self._last_update, 

684 self._next_update, 

685 self._extensions, 

686 [*self._revoked_certificates, revoked_certificate], 

687 ) 

688 

689 def sign( 

690 self, 

691 private_key: CertificateIssuerPrivateKeyTypes, 

692 algorithm: _AllowedHashTypes | None, 

693 backend: typing.Any = None, 

694 *, 

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

696 ecdsa_deterministic: bool | None = None, 

697 ) -> CertificateRevocationList: 

698 if self._issuer_name is None: 

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

700 

701 if self._last_update is None: 

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

703 

704 if self._next_update is None: 

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

706 

707 if rsa_padding is not None: 

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

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

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

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

712 

713 if ecdsa_deterministic is not None: 

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

715 raise TypeError( 

716 "Deterministic ECDSA is only supported for EC keys" 

717 ) 

718 

719 return rust_x509.create_x509_crl( 

720 self, 

721 private_key, 

722 algorithm, 

723 rsa_padding, 

724 ecdsa_deterministic, 

725 ) 

726 

727 

728class RevokedCertificateBuilder: 

729 def __init__( 

730 self, 

731 serial_number: int | None = None, 

732 revocation_date: datetime.datetime | None = None, 

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

734 ): 

735 self._serial_number = serial_number 

736 self._revocation_date = revocation_date 

737 self._extensions = extensions 

738 

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

740 if not isinstance(number, int): 

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

742 if self._serial_number is not None: 

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

744 if number <= 0: 

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

746 

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

748 # zero. 

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

750 raise ValueError( 

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

752 ) 

753 return RevokedCertificateBuilder( 

754 number, self._revocation_date, self._extensions 

755 ) 

756 

757 def revocation_date( 

758 self, time: datetime.datetime 

759 ) -> RevokedCertificateBuilder: 

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

761 raise TypeError("Expecting datetime object.") 

762 if self._revocation_date is not None: 

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

764 time = _convert_to_naive_utc_time(time) 

765 if time < _EARLIEST_UTC_TIME: 

766 raise ValueError( 

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

768 ) 

769 return RevokedCertificateBuilder( 

770 self._serial_number, time, self._extensions 

771 ) 

772 

773 def add_extension( 

774 self, extval: ExtensionType, critical: bool 

775 ) -> RevokedCertificateBuilder: 

776 if not isinstance(extval, ExtensionType): 

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

778 

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

780 _reject_duplicate_extension(extension, self._extensions) 

781 return RevokedCertificateBuilder( 

782 self._serial_number, 

783 self._revocation_date, 

784 [*self._extensions, extension], 

785 ) 

786 

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

788 if self._serial_number is None: 

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

790 if self._revocation_date is None: 

791 raise ValueError( 

792 "A revoked certificate must have a revocation date" 

793 ) 

794 return rust_x509.create_revoked_certificate(self) 

795 

796 

797def random_serial_number() -> int: 

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