Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/x509/extensions.py: 45%

989 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2023-03-26 06:36 +0000

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 

5 

6import abc 

7import datetime 

8import hashlib 

9import ipaddress 

10import typing 

11 

12from cryptography import utils 

13from cryptography.hazmat.bindings._rust import asn1 

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

15from cryptography.hazmat.primitives import constant_time, serialization 

16from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey 

17from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey 

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

19 CertificateIssuerPublicKeyTypes, 

20 CertificatePublicKeyTypes, 

21) 

22from cryptography.x509.certificate_transparency import ( 

23 SignedCertificateTimestamp, 

24) 

25from cryptography.x509.general_name import ( 

26 DirectoryName, 

27 DNSName, 

28 GeneralName, 

29 IPAddress, 

30 OtherName, 

31 RegisteredID, 

32 RFC822Name, 

33 UniformResourceIdentifier, 

34 _IPAddressTypes, 

35) 

36from cryptography.x509.name import Name, RelativeDistinguishedName 

37from cryptography.x509.oid import ( 

38 CRLEntryExtensionOID, 

39 ExtensionOID, 

40 ObjectIdentifier, 

41 OCSPExtensionOID, 

42) 

43 

44ExtensionTypeVar = typing.TypeVar( 

45 "ExtensionTypeVar", bound="ExtensionType", covariant=True 

46) 

47 

48 

49def _key_identifier_from_public_key( 

50 public_key: CertificatePublicKeyTypes, 

51) -> bytes: 

52 if isinstance(public_key, RSAPublicKey): 

53 data = public_key.public_bytes( 

54 serialization.Encoding.DER, 

55 serialization.PublicFormat.PKCS1, 

56 ) 

57 elif isinstance(public_key, EllipticCurvePublicKey): 

58 data = public_key.public_bytes( 

59 serialization.Encoding.X962, 

60 serialization.PublicFormat.UncompressedPoint, 

61 ) 

62 else: 

63 # This is a very slow way to do this. 

64 serialized = public_key.public_bytes( 

65 serialization.Encoding.DER, 

66 serialization.PublicFormat.SubjectPublicKeyInfo, 

67 ) 

68 data = asn1.parse_spki_for_data(serialized) 

69 

70 return hashlib.sha1(data).digest() 

71 

72 

73def _make_sequence_methods(field_name: str): 

74 def len_method(self) -> int: 

75 return len(getattr(self, field_name)) 

76 

77 def iter_method(self): 

78 return iter(getattr(self, field_name)) 

79 

80 def getitem_method(self, idx): 

81 return getattr(self, field_name)[idx] 

82 

83 return len_method, iter_method, getitem_method 

84 

85 

86class DuplicateExtension(Exception): 

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

88 super().__init__(msg) 

89 self.oid = oid 

90 

91 

92class ExtensionNotFound(Exception): 

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

94 super().__init__(msg) 

95 self.oid = oid 

96 

97 

98class ExtensionType(metaclass=abc.ABCMeta): 

99 oid: typing.ClassVar[ObjectIdentifier] 

100 

101 def public_bytes(self) -> bytes: 

102 """ 

103 Serializes the extension type to DER. 

104 """ 

105 raise NotImplementedError( 

106 "public_bytes is not implemented for extension type {!r}".format( 

107 self 

108 ) 

109 ) 

110 

111 

112class Extensions: 

113 def __init__( 

114 self, extensions: typing.Iterable["Extension[ExtensionType]"] 

115 ) -> None: 

116 self._extensions = list(extensions) 

117 

118 def get_extension_for_oid( 

119 self, oid: ObjectIdentifier 

120 ) -> "Extension[ExtensionType]": 

121 for ext in self: 

122 if ext.oid == oid: 

123 return ext 

124 

125 raise ExtensionNotFound(f"No {oid} extension was found", oid) 

126 

127 def get_extension_for_class( 

128 self, extclass: typing.Type[ExtensionTypeVar] 

129 ) -> "Extension[ExtensionTypeVar]": 

130 if extclass is UnrecognizedExtension: 

131 raise TypeError( 

132 "UnrecognizedExtension can't be used with " 

133 "get_extension_for_class because more than one instance of the" 

134 " class may be present." 

135 ) 

136 

137 for ext in self: 

138 if isinstance(ext.value, extclass): 

139 return ext 

140 

141 raise ExtensionNotFound( 

142 f"No {extclass} extension was found", extclass.oid 

143 ) 

144 

145 __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions") 

146 

147 def __repr__(self) -> str: 

148 return f"<Extensions({self._extensions})>" 

149 

150 

151class CRLNumber(ExtensionType): 

152 oid = ExtensionOID.CRL_NUMBER 

153 

154 def __init__(self, crl_number: int) -> None: 

155 if not isinstance(crl_number, int): 

156 raise TypeError("crl_number must be an integer") 

157 

158 self._crl_number = crl_number 

159 

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

161 if not isinstance(other, CRLNumber): 

162 return NotImplemented 

163 

164 return self.crl_number == other.crl_number 

165 

166 def __hash__(self) -> int: 

167 return hash(self.crl_number) 

168 

169 def __repr__(self) -> str: 

170 return f"<CRLNumber({self.crl_number})>" 

171 

172 @property 

173 def crl_number(self) -> int: 

174 return self._crl_number 

175 

176 def public_bytes(self) -> bytes: 

177 return rust_x509.encode_extension_value(self) 

178 

179 

180class AuthorityKeyIdentifier(ExtensionType): 

181 oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER 

182 

183 def __init__( 

184 self, 

185 key_identifier: typing.Optional[bytes], 

186 authority_cert_issuer: typing.Optional[typing.Iterable[GeneralName]], 

187 authority_cert_serial_number: typing.Optional[int], 

188 ) -> None: 

189 if (authority_cert_issuer is None) != ( 

190 authority_cert_serial_number is None 

191 ): 

192 raise ValueError( 

193 "authority_cert_issuer and authority_cert_serial_number " 

194 "must both be present or both None" 

195 ) 

196 

197 if authority_cert_issuer is not None: 

198 authority_cert_issuer = list(authority_cert_issuer) 

199 if not all( 

200 isinstance(x, GeneralName) for x in authority_cert_issuer 

201 ): 

202 raise TypeError( 

203 "authority_cert_issuer must be a list of GeneralName " 

204 "objects" 

205 ) 

206 

207 if authority_cert_serial_number is not None and not isinstance( 

208 authority_cert_serial_number, int 

209 ): 

210 raise TypeError("authority_cert_serial_number must be an integer") 

211 

212 self._key_identifier = key_identifier 

213 self._authority_cert_issuer = authority_cert_issuer 

214 self._authority_cert_serial_number = authority_cert_serial_number 

215 

216 # This takes a subset of CertificatePublicKeyTypes because an issuer 

217 # cannot have an X25519/X448 key. This introduces some unfortunate 

218 # asymmetry that requires typing users to explicitly 

219 # narrow their type, but we should make this accurate and not just 

220 # convenient. 

221 @classmethod 

222 def from_issuer_public_key( 

223 cls, public_key: CertificateIssuerPublicKeyTypes 

224 ) -> "AuthorityKeyIdentifier": 

225 digest = _key_identifier_from_public_key(public_key) 

226 return cls( 

227 key_identifier=digest, 

228 authority_cert_issuer=None, 

229 authority_cert_serial_number=None, 

230 ) 

231 

232 @classmethod 

233 def from_issuer_subject_key_identifier( 

234 cls, ski: "SubjectKeyIdentifier" 

235 ) -> "AuthorityKeyIdentifier": 

236 return cls( 

237 key_identifier=ski.digest, 

238 authority_cert_issuer=None, 

239 authority_cert_serial_number=None, 

240 ) 

241 

242 def __repr__(self) -> str: 

243 return ( 

244 "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, " 

245 "authority_cert_issuer={0.authority_cert_issuer}, " 

246 "authority_cert_serial_number={0.authority_cert_serial_number}" 

247 ")>".format(self) 

248 ) 

249 

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

251 if not isinstance(other, AuthorityKeyIdentifier): 

252 return NotImplemented 

253 

254 return ( 

255 self.key_identifier == other.key_identifier 

256 and self.authority_cert_issuer == other.authority_cert_issuer 

257 and self.authority_cert_serial_number 

258 == other.authority_cert_serial_number 

259 ) 

260 

261 def __hash__(self) -> int: 

262 if self.authority_cert_issuer is None: 

263 aci = None 

264 else: 

265 aci = tuple(self.authority_cert_issuer) 

266 return hash( 

267 (self.key_identifier, aci, self.authority_cert_serial_number) 

268 ) 

269 

270 @property 

271 def key_identifier(self) -> typing.Optional[bytes]: 

272 return self._key_identifier 

273 

274 @property 

275 def authority_cert_issuer( 

276 self, 

277 ) -> typing.Optional[typing.List[GeneralName]]: 

278 return self._authority_cert_issuer 

279 

280 @property 

281 def authority_cert_serial_number(self) -> typing.Optional[int]: 

282 return self._authority_cert_serial_number 

283 

284 def public_bytes(self) -> bytes: 

285 return rust_x509.encode_extension_value(self) 

286 

287 

288class SubjectKeyIdentifier(ExtensionType): 

289 oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER 

290 

291 def __init__(self, digest: bytes) -> None: 

292 self._digest = digest 

293 

294 @classmethod 

295 def from_public_key( 

296 cls, public_key: CertificatePublicKeyTypes 

297 ) -> "SubjectKeyIdentifier": 

298 return cls(_key_identifier_from_public_key(public_key)) 

299 

300 @property 

301 def digest(self) -> bytes: 

302 return self._digest 

303 

304 @property 

305 def key_identifier(self) -> bytes: 

306 return self._digest 

307 

308 def __repr__(self) -> str: 

309 return f"<SubjectKeyIdentifier(digest={self.digest!r})>" 

310 

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

312 if not isinstance(other, SubjectKeyIdentifier): 

313 return NotImplemented 

314 

315 return constant_time.bytes_eq(self.digest, other.digest) 

316 

317 def __hash__(self) -> int: 

318 return hash(self.digest) 

319 

320 def public_bytes(self) -> bytes: 

321 return rust_x509.encode_extension_value(self) 

322 

323 

324class AuthorityInformationAccess(ExtensionType): 

325 oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS 

326 

327 def __init__( 

328 self, descriptions: typing.Iterable["AccessDescription"] 

329 ) -> None: 

330 descriptions = list(descriptions) 

331 if not all(isinstance(x, AccessDescription) for x in descriptions): 

332 raise TypeError( 

333 "Every item in the descriptions list must be an " 

334 "AccessDescription" 

335 ) 

336 

337 self._descriptions = descriptions 

338 

339 __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") 

340 

341 def __repr__(self) -> str: 

342 return f"<AuthorityInformationAccess({self._descriptions})>" 

343 

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

345 if not isinstance(other, AuthorityInformationAccess): 

346 return NotImplemented 

347 

348 return self._descriptions == other._descriptions 

349 

350 def __hash__(self) -> int: 

351 return hash(tuple(self._descriptions)) 

352 

353 def public_bytes(self) -> bytes: 

354 return rust_x509.encode_extension_value(self) 

355 

356 

357class SubjectInformationAccess(ExtensionType): 

358 oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS 

359 

360 def __init__( 

361 self, descriptions: typing.Iterable["AccessDescription"] 

362 ) -> None: 

363 descriptions = list(descriptions) 

364 if not all(isinstance(x, AccessDescription) for x in descriptions): 

365 raise TypeError( 

366 "Every item in the descriptions list must be an " 

367 "AccessDescription" 

368 ) 

369 

370 self._descriptions = descriptions 

371 

372 __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") 

373 

374 def __repr__(self) -> str: 

375 return f"<SubjectInformationAccess({self._descriptions})>" 

376 

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

378 if not isinstance(other, SubjectInformationAccess): 

379 return NotImplemented 

380 

381 return self._descriptions == other._descriptions 

382 

383 def __hash__(self) -> int: 

384 return hash(tuple(self._descriptions)) 

385 

386 def public_bytes(self) -> bytes: 

387 return rust_x509.encode_extension_value(self) 

388 

389 

390class AccessDescription: 

391 def __init__( 

392 self, access_method: ObjectIdentifier, access_location: GeneralName 

393 ) -> None: 

394 if not isinstance(access_method, ObjectIdentifier): 

395 raise TypeError("access_method must be an ObjectIdentifier") 

396 

397 if not isinstance(access_location, GeneralName): 

398 raise TypeError("access_location must be a GeneralName") 

399 

400 self._access_method = access_method 

401 self._access_location = access_location 

402 

403 def __repr__(self) -> str: 

404 return ( 

405 "<AccessDescription(access_method={0.access_method}, access_locati" 

406 "on={0.access_location})>".format(self) 

407 ) 

408 

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

410 if not isinstance(other, AccessDescription): 

411 return NotImplemented 

412 

413 return ( 

414 self.access_method == other.access_method 

415 and self.access_location == other.access_location 

416 ) 

417 

418 def __hash__(self) -> int: 

419 return hash((self.access_method, self.access_location)) 

420 

421 @property 

422 def access_method(self) -> ObjectIdentifier: 

423 return self._access_method 

424 

425 @property 

426 def access_location(self) -> GeneralName: 

427 return self._access_location 

428 

429 

430class BasicConstraints(ExtensionType): 

431 oid = ExtensionOID.BASIC_CONSTRAINTS 

432 

433 def __init__(self, ca: bool, path_length: typing.Optional[int]) -> None: 

434 if not isinstance(ca, bool): 

435 raise TypeError("ca must be a boolean value") 

436 

437 if path_length is not None and not ca: 

438 raise ValueError("path_length must be None when ca is False") 

439 

440 if path_length is not None and ( 

441 not isinstance(path_length, int) or path_length < 0 

442 ): 

443 raise TypeError( 

444 "path_length must be a non-negative integer or None" 

445 ) 

446 

447 self._ca = ca 

448 self._path_length = path_length 

449 

450 @property 

451 def ca(self) -> bool: 

452 return self._ca 

453 

454 @property 

455 def path_length(self) -> typing.Optional[int]: 

456 return self._path_length 

457 

458 def __repr__(self) -> str: 

459 return ( 

460 "<BasicConstraints(ca={0.ca}, " "path_length={0.path_length})>" 

461 ).format(self) 

462 

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

464 if not isinstance(other, BasicConstraints): 

465 return NotImplemented 

466 

467 return self.ca == other.ca and self.path_length == other.path_length 

468 

469 def __hash__(self) -> int: 

470 return hash((self.ca, self.path_length)) 

471 

472 def public_bytes(self) -> bytes: 

473 return rust_x509.encode_extension_value(self) 

474 

475 

476class DeltaCRLIndicator(ExtensionType): 

477 oid = ExtensionOID.DELTA_CRL_INDICATOR 

478 

479 def __init__(self, crl_number: int) -> None: 

480 if not isinstance(crl_number, int): 

481 raise TypeError("crl_number must be an integer") 

482 

483 self._crl_number = crl_number 

484 

485 @property 

486 def crl_number(self) -> int: 

487 return self._crl_number 

488 

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

490 if not isinstance(other, DeltaCRLIndicator): 

491 return NotImplemented 

492 

493 return self.crl_number == other.crl_number 

494 

495 def __hash__(self) -> int: 

496 return hash(self.crl_number) 

497 

498 def __repr__(self) -> str: 

499 return f"<DeltaCRLIndicator(crl_number={self.crl_number})>" 

500 

501 def public_bytes(self) -> bytes: 

502 return rust_x509.encode_extension_value(self) 

503 

504 

505class CRLDistributionPoints(ExtensionType): 

506 oid = ExtensionOID.CRL_DISTRIBUTION_POINTS 

507 

508 def __init__( 

509 self, distribution_points: typing.Iterable["DistributionPoint"] 

510 ) -> None: 

511 distribution_points = list(distribution_points) 

512 if not all( 

513 isinstance(x, DistributionPoint) for x in distribution_points 

514 ): 

515 raise TypeError( 

516 "distribution_points must be a list of DistributionPoint " 

517 "objects" 

518 ) 

519 

520 self._distribution_points = distribution_points 

521 

522 __len__, __iter__, __getitem__ = _make_sequence_methods( 

523 "_distribution_points" 

524 ) 

525 

526 def __repr__(self) -> str: 

527 return f"<CRLDistributionPoints({self._distribution_points})>" 

528 

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

530 if not isinstance(other, CRLDistributionPoints): 

531 return NotImplemented 

532 

533 return self._distribution_points == other._distribution_points 

534 

535 def __hash__(self) -> int: 

536 return hash(tuple(self._distribution_points)) 

537 

538 def public_bytes(self) -> bytes: 

539 return rust_x509.encode_extension_value(self) 

540 

541 

542class FreshestCRL(ExtensionType): 

543 oid = ExtensionOID.FRESHEST_CRL 

544 

545 def __init__( 

546 self, distribution_points: typing.Iterable["DistributionPoint"] 

547 ) -> None: 

548 distribution_points = list(distribution_points) 

549 if not all( 

550 isinstance(x, DistributionPoint) for x in distribution_points 

551 ): 

552 raise TypeError( 

553 "distribution_points must be a list of DistributionPoint " 

554 "objects" 

555 ) 

556 

557 self._distribution_points = distribution_points 

558 

559 __len__, __iter__, __getitem__ = _make_sequence_methods( 

560 "_distribution_points" 

561 ) 

562 

563 def __repr__(self) -> str: 

564 return f"<FreshestCRL({self._distribution_points})>" 

565 

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

567 if not isinstance(other, FreshestCRL): 

568 return NotImplemented 

569 

570 return self._distribution_points == other._distribution_points 

571 

572 def __hash__(self) -> int: 

573 return hash(tuple(self._distribution_points)) 

574 

575 def public_bytes(self) -> bytes: 

576 return rust_x509.encode_extension_value(self) 

577 

578 

579class DistributionPoint: 

580 def __init__( 

581 self, 

582 full_name: typing.Optional[typing.Iterable[GeneralName]], 

583 relative_name: typing.Optional[RelativeDistinguishedName], 

584 reasons: typing.Optional[typing.FrozenSet["ReasonFlags"]], 

585 crl_issuer: typing.Optional[typing.Iterable[GeneralName]], 

586 ) -> None: 

587 if full_name and relative_name: 

588 raise ValueError( 

589 "You cannot provide both full_name and relative_name, at " 

590 "least one must be None." 

591 ) 

592 if not full_name and not relative_name and not crl_issuer: 

593 raise ValueError( 

594 "Either full_name, relative_name or crl_issuer must be " 

595 "provided." 

596 ) 

597 

598 if full_name is not None: 

599 full_name = list(full_name) 

600 if not all(isinstance(x, GeneralName) for x in full_name): 

601 raise TypeError( 

602 "full_name must be a list of GeneralName objects" 

603 ) 

604 

605 if relative_name: 

606 if not isinstance(relative_name, RelativeDistinguishedName): 

607 raise TypeError( 

608 "relative_name must be a RelativeDistinguishedName" 

609 ) 

610 

611 if crl_issuer is not None: 

612 crl_issuer = list(crl_issuer) 

613 if not all(isinstance(x, GeneralName) for x in crl_issuer): 

614 raise TypeError( 

615 "crl_issuer must be None or a list of general names" 

616 ) 

617 

618 if reasons and ( 

619 not isinstance(reasons, frozenset) 

620 or not all(isinstance(x, ReasonFlags) for x in reasons) 

621 ): 

622 raise TypeError("reasons must be None or frozenset of ReasonFlags") 

623 

624 if reasons and ( 

625 ReasonFlags.unspecified in reasons 

626 or ReasonFlags.remove_from_crl in reasons 

627 ): 

628 raise ValueError( 

629 "unspecified and remove_from_crl are not valid reasons in a " 

630 "DistributionPoint" 

631 ) 

632 

633 self._full_name = full_name 

634 self._relative_name = relative_name 

635 self._reasons = reasons 

636 self._crl_issuer = crl_issuer 

637 

638 def __repr__(self) -> str: 

639 return ( 

640 "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela" 

641 "tive_name}, reasons={0.reasons}, " 

642 "crl_issuer={0.crl_issuer})>".format(self) 

643 ) 

644 

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

646 if not isinstance(other, DistributionPoint): 

647 return NotImplemented 

648 

649 return ( 

650 self.full_name == other.full_name 

651 and self.relative_name == other.relative_name 

652 and self.reasons == other.reasons 

653 and self.crl_issuer == other.crl_issuer 

654 ) 

655 

656 def __hash__(self) -> int: 

657 if self.full_name is not None: 

658 fn: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple( 

659 self.full_name 

660 ) 

661 else: 

662 fn = None 

663 

664 if self.crl_issuer is not None: 

665 crl_issuer: typing.Optional[ 

666 typing.Tuple[GeneralName, ...] 

667 ] = tuple(self.crl_issuer) 

668 else: 

669 crl_issuer = None 

670 

671 return hash((fn, self.relative_name, self.reasons, crl_issuer)) 

672 

673 @property 

674 def full_name(self) -> typing.Optional[typing.List[GeneralName]]: 

675 return self._full_name 

676 

677 @property 

678 def relative_name(self) -> typing.Optional[RelativeDistinguishedName]: 

679 return self._relative_name 

680 

681 @property 

682 def reasons(self) -> typing.Optional[typing.FrozenSet["ReasonFlags"]]: 

683 return self._reasons 

684 

685 @property 

686 def crl_issuer(self) -> typing.Optional[typing.List[GeneralName]]: 

687 return self._crl_issuer 

688 

689 

690class ReasonFlags(utils.Enum): 

691 unspecified = "unspecified" 

692 key_compromise = "keyCompromise" 

693 ca_compromise = "cACompromise" 

694 affiliation_changed = "affiliationChanged" 

695 superseded = "superseded" 

696 cessation_of_operation = "cessationOfOperation" 

697 certificate_hold = "certificateHold" 

698 privilege_withdrawn = "privilegeWithdrawn" 

699 aa_compromise = "aACompromise" 

700 remove_from_crl = "removeFromCRL" 

701 

702 

703# These are distribution point bit string mappings. Not to be confused with 

704# CRLReason reason flags bit string mappings. 

705# ReasonFlags ::= BIT STRING { 

706# unused (0), 

707# keyCompromise (1), 

708# cACompromise (2), 

709# affiliationChanged (3), 

710# superseded (4), 

711# cessationOfOperation (5), 

712# certificateHold (6), 

713# privilegeWithdrawn (7), 

714# aACompromise (8) } 

715_REASON_BIT_MAPPING = { 

716 1: ReasonFlags.key_compromise, 

717 2: ReasonFlags.ca_compromise, 

718 3: ReasonFlags.affiliation_changed, 

719 4: ReasonFlags.superseded, 

720 5: ReasonFlags.cessation_of_operation, 

721 6: ReasonFlags.certificate_hold, 

722 7: ReasonFlags.privilege_withdrawn, 

723 8: ReasonFlags.aa_compromise, 

724} 

725 

726_CRLREASONFLAGS = { 

727 ReasonFlags.key_compromise: 1, 

728 ReasonFlags.ca_compromise: 2, 

729 ReasonFlags.affiliation_changed: 3, 

730 ReasonFlags.superseded: 4, 

731 ReasonFlags.cessation_of_operation: 5, 

732 ReasonFlags.certificate_hold: 6, 

733 ReasonFlags.privilege_withdrawn: 7, 

734 ReasonFlags.aa_compromise: 8, 

735} 

736 

737 

738class PolicyConstraints(ExtensionType): 

739 oid = ExtensionOID.POLICY_CONSTRAINTS 

740 

741 def __init__( 

742 self, 

743 require_explicit_policy: typing.Optional[int], 

744 inhibit_policy_mapping: typing.Optional[int], 

745 ) -> None: 

746 if require_explicit_policy is not None and not isinstance( 

747 require_explicit_policy, int 

748 ): 

749 raise TypeError( 

750 "require_explicit_policy must be a non-negative integer or " 

751 "None" 

752 ) 

753 

754 if inhibit_policy_mapping is not None and not isinstance( 

755 inhibit_policy_mapping, int 

756 ): 

757 raise TypeError( 

758 "inhibit_policy_mapping must be a non-negative integer or None" 

759 ) 

760 

761 if inhibit_policy_mapping is None and require_explicit_policy is None: 

762 raise ValueError( 

763 "At least one of require_explicit_policy and " 

764 "inhibit_policy_mapping must not be None" 

765 ) 

766 

767 self._require_explicit_policy = require_explicit_policy 

768 self._inhibit_policy_mapping = inhibit_policy_mapping 

769 

770 def __repr__(self) -> str: 

771 return ( 

772 "<PolicyConstraints(require_explicit_policy={0.require_explicit" 

773 "_policy}, inhibit_policy_mapping={0.inhibit_policy_" 

774 "mapping})>".format(self) 

775 ) 

776 

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

778 if not isinstance(other, PolicyConstraints): 

779 return NotImplemented 

780 

781 return ( 

782 self.require_explicit_policy == other.require_explicit_policy 

783 and self.inhibit_policy_mapping == other.inhibit_policy_mapping 

784 ) 

785 

786 def __hash__(self) -> int: 

787 return hash( 

788 (self.require_explicit_policy, self.inhibit_policy_mapping) 

789 ) 

790 

791 @property 

792 def require_explicit_policy(self) -> typing.Optional[int]: 

793 return self._require_explicit_policy 

794 

795 @property 

796 def inhibit_policy_mapping(self) -> typing.Optional[int]: 

797 return self._inhibit_policy_mapping 

798 

799 def public_bytes(self) -> bytes: 

800 return rust_x509.encode_extension_value(self) 

801 

802 

803class CertificatePolicies(ExtensionType): 

804 oid = ExtensionOID.CERTIFICATE_POLICIES 

805 

806 def __init__(self, policies: typing.Iterable["PolicyInformation"]) -> None: 

807 policies = list(policies) 

808 if not all(isinstance(x, PolicyInformation) for x in policies): 

809 raise TypeError( 

810 "Every item in the policies list must be a " 

811 "PolicyInformation" 

812 ) 

813 

814 self._policies = policies 

815 

816 __len__, __iter__, __getitem__ = _make_sequence_methods("_policies") 

817 

818 def __repr__(self) -> str: 

819 return f"<CertificatePolicies({self._policies})>" 

820 

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

822 if not isinstance(other, CertificatePolicies): 

823 return NotImplemented 

824 

825 return self._policies == other._policies 

826 

827 def __hash__(self) -> int: 

828 return hash(tuple(self._policies)) 

829 

830 def public_bytes(self) -> bytes: 

831 return rust_x509.encode_extension_value(self) 

832 

833 

834class PolicyInformation: 

835 def __init__( 

836 self, 

837 policy_identifier: ObjectIdentifier, 

838 policy_qualifiers: typing.Optional[ 

839 typing.Iterable[typing.Union[str, "UserNotice"]] 

840 ], 

841 ) -> None: 

842 if not isinstance(policy_identifier, ObjectIdentifier): 

843 raise TypeError("policy_identifier must be an ObjectIdentifier") 

844 

845 self._policy_identifier = policy_identifier 

846 

847 if policy_qualifiers is not None: 

848 policy_qualifiers = list(policy_qualifiers) 

849 if not all( 

850 isinstance(x, (str, UserNotice)) for x in policy_qualifiers 

851 ): 

852 raise TypeError( 

853 "policy_qualifiers must be a list of strings and/or " 

854 "UserNotice objects or None" 

855 ) 

856 

857 self._policy_qualifiers = policy_qualifiers 

858 

859 def __repr__(self) -> str: 

860 return ( 

861 "<PolicyInformation(policy_identifier={0.policy_identifier}, polic" 

862 "y_qualifiers={0.policy_qualifiers})>".format(self) 

863 ) 

864 

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

866 if not isinstance(other, PolicyInformation): 

867 return NotImplemented 

868 

869 return ( 

870 self.policy_identifier == other.policy_identifier 

871 and self.policy_qualifiers == other.policy_qualifiers 

872 ) 

873 

874 def __hash__(self) -> int: 

875 if self.policy_qualifiers is not None: 

876 pq: typing.Optional[ 

877 typing.Tuple[typing.Union[str, "UserNotice"], ...] 

878 ] = tuple(self.policy_qualifiers) 

879 else: 

880 pq = None 

881 

882 return hash((self.policy_identifier, pq)) 

883 

884 @property 

885 def policy_identifier(self) -> ObjectIdentifier: 

886 return self._policy_identifier 

887 

888 @property 

889 def policy_qualifiers( 

890 self, 

891 ) -> typing.Optional[typing.List[typing.Union[str, "UserNotice"]]]: 

892 return self._policy_qualifiers 

893 

894 

895class UserNotice: 

896 def __init__( 

897 self, 

898 notice_reference: typing.Optional["NoticeReference"], 

899 explicit_text: typing.Optional[str], 

900 ) -> None: 

901 if notice_reference and not isinstance( 

902 notice_reference, NoticeReference 

903 ): 

904 raise TypeError( 

905 "notice_reference must be None or a NoticeReference" 

906 ) 

907 

908 self._notice_reference = notice_reference 

909 self._explicit_text = explicit_text 

910 

911 def __repr__(self) -> str: 

912 return ( 

913 "<UserNotice(notice_reference={0.notice_reference}, explicit_text=" 

914 "{0.explicit_text!r})>".format(self) 

915 ) 

916 

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

918 if not isinstance(other, UserNotice): 

919 return NotImplemented 

920 

921 return ( 

922 self.notice_reference == other.notice_reference 

923 and self.explicit_text == other.explicit_text 

924 ) 

925 

926 def __hash__(self) -> int: 

927 return hash((self.notice_reference, self.explicit_text)) 

928 

929 @property 

930 def notice_reference(self) -> typing.Optional["NoticeReference"]: 

931 return self._notice_reference 

932 

933 @property 

934 def explicit_text(self) -> typing.Optional[str]: 

935 return self._explicit_text 

936 

937 

938class NoticeReference: 

939 def __init__( 

940 self, 

941 organization: typing.Optional[str], 

942 notice_numbers: typing.Iterable[int], 

943 ) -> None: 

944 self._organization = organization 

945 notice_numbers = list(notice_numbers) 

946 if not all(isinstance(x, int) for x in notice_numbers): 

947 raise TypeError("notice_numbers must be a list of integers") 

948 

949 self._notice_numbers = notice_numbers 

950 

951 def __repr__(self) -> str: 

952 return ( 

953 "<NoticeReference(organization={0.organization!r}, notice_numbers=" 

954 "{0.notice_numbers})>".format(self) 

955 ) 

956 

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

958 if not isinstance(other, NoticeReference): 

959 return NotImplemented 

960 

961 return ( 

962 self.organization == other.organization 

963 and self.notice_numbers == other.notice_numbers 

964 ) 

965 

966 def __hash__(self) -> int: 

967 return hash((self.organization, tuple(self.notice_numbers))) 

968 

969 @property 

970 def organization(self) -> typing.Optional[str]: 

971 return self._organization 

972 

973 @property 

974 def notice_numbers(self) -> typing.List[int]: 

975 return self._notice_numbers 

976 

977 

978class ExtendedKeyUsage(ExtensionType): 

979 oid = ExtensionOID.EXTENDED_KEY_USAGE 

980 

981 def __init__(self, usages: typing.Iterable[ObjectIdentifier]) -> None: 

982 usages = list(usages) 

983 if not all(isinstance(x, ObjectIdentifier) for x in usages): 

984 raise TypeError( 

985 "Every item in the usages list must be an ObjectIdentifier" 

986 ) 

987 

988 self._usages = usages 

989 

990 __len__, __iter__, __getitem__ = _make_sequence_methods("_usages") 

991 

992 def __repr__(self) -> str: 

993 return f"<ExtendedKeyUsage({self._usages})>" 

994 

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

996 if not isinstance(other, ExtendedKeyUsage): 

997 return NotImplemented 

998 

999 return self._usages == other._usages 

1000 

1001 def __hash__(self) -> int: 

1002 return hash(tuple(self._usages)) 

1003 

1004 def public_bytes(self) -> bytes: 

1005 return rust_x509.encode_extension_value(self) 

1006 

1007 

1008class OCSPNoCheck(ExtensionType): 

1009 oid = ExtensionOID.OCSP_NO_CHECK 

1010 

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

1012 if not isinstance(other, OCSPNoCheck): 

1013 return NotImplemented 

1014 

1015 return True 

1016 

1017 def __hash__(self) -> int: 

1018 return hash(OCSPNoCheck) 

1019 

1020 def __repr__(self) -> str: 

1021 return "<OCSPNoCheck()>" 

1022 

1023 def public_bytes(self) -> bytes: 

1024 return rust_x509.encode_extension_value(self) 

1025 

1026 

1027class PrecertPoison(ExtensionType): 

1028 oid = ExtensionOID.PRECERT_POISON 

1029 

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

1031 if not isinstance(other, PrecertPoison): 

1032 return NotImplemented 

1033 

1034 return True 

1035 

1036 def __hash__(self) -> int: 

1037 return hash(PrecertPoison) 

1038 

1039 def __repr__(self) -> str: 

1040 return "<PrecertPoison()>" 

1041 

1042 def public_bytes(self) -> bytes: 

1043 return rust_x509.encode_extension_value(self) 

1044 

1045 

1046class TLSFeature(ExtensionType): 

1047 oid = ExtensionOID.TLS_FEATURE 

1048 

1049 def __init__(self, features: typing.Iterable["TLSFeatureType"]) -> None: 

1050 features = list(features) 

1051 if ( 

1052 not all(isinstance(x, TLSFeatureType) for x in features) 

1053 or len(features) == 0 

1054 ): 

1055 raise TypeError( 

1056 "features must be a list of elements from the TLSFeatureType " 

1057 "enum" 

1058 ) 

1059 

1060 self._features = features 

1061 

1062 __len__, __iter__, __getitem__ = _make_sequence_methods("_features") 

1063 

1064 def __repr__(self) -> str: 

1065 return f"<TLSFeature(features={self._features})>" 

1066 

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

1068 if not isinstance(other, TLSFeature): 

1069 return NotImplemented 

1070 

1071 return self._features == other._features 

1072 

1073 def __hash__(self) -> int: 

1074 return hash(tuple(self._features)) 

1075 

1076 def public_bytes(self) -> bytes: 

1077 return rust_x509.encode_extension_value(self) 

1078 

1079 

1080class TLSFeatureType(utils.Enum): 

1081 # status_request is defined in RFC 6066 and is used for what is commonly 

1082 # called OCSP Must-Staple when present in the TLS Feature extension in an 

1083 # X.509 certificate. 

1084 status_request = 5 

1085 # status_request_v2 is defined in RFC 6961 and allows multiple OCSP 

1086 # responses to be provided. It is not currently in use by clients or 

1087 # servers. 

1088 status_request_v2 = 17 

1089 

1090 

1091_TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType} 

1092 

1093 

1094class InhibitAnyPolicy(ExtensionType): 

1095 oid = ExtensionOID.INHIBIT_ANY_POLICY 

1096 

1097 def __init__(self, skip_certs: int) -> None: 

1098 if not isinstance(skip_certs, int): 

1099 raise TypeError("skip_certs must be an integer") 

1100 

1101 if skip_certs < 0: 

1102 raise ValueError("skip_certs must be a non-negative integer") 

1103 

1104 self._skip_certs = skip_certs 

1105 

1106 def __repr__(self) -> str: 

1107 return f"<InhibitAnyPolicy(skip_certs={self.skip_certs})>" 

1108 

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

1110 if not isinstance(other, InhibitAnyPolicy): 

1111 return NotImplemented 

1112 

1113 return self.skip_certs == other.skip_certs 

1114 

1115 def __hash__(self) -> int: 

1116 return hash(self.skip_certs) 

1117 

1118 @property 

1119 def skip_certs(self) -> int: 

1120 return self._skip_certs 

1121 

1122 def public_bytes(self) -> bytes: 

1123 return rust_x509.encode_extension_value(self) 

1124 

1125 

1126class KeyUsage(ExtensionType): 

1127 oid = ExtensionOID.KEY_USAGE 

1128 

1129 def __init__( 

1130 self, 

1131 digital_signature: bool, 

1132 content_commitment: bool, 

1133 key_encipherment: bool, 

1134 data_encipherment: bool, 

1135 key_agreement: bool, 

1136 key_cert_sign: bool, 

1137 crl_sign: bool, 

1138 encipher_only: bool, 

1139 decipher_only: bool, 

1140 ) -> None: 

1141 if not key_agreement and (encipher_only or decipher_only): 

1142 raise ValueError( 

1143 "encipher_only and decipher_only can only be true when " 

1144 "key_agreement is true" 

1145 ) 

1146 

1147 self._digital_signature = digital_signature 

1148 self._content_commitment = content_commitment 

1149 self._key_encipherment = key_encipherment 

1150 self._data_encipherment = data_encipherment 

1151 self._key_agreement = key_agreement 

1152 self._key_cert_sign = key_cert_sign 

1153 self._crl_sign = crl_sign 

1154 self._encipher_only = encipher_only 

1155 self._decipher_only = decipher_only 

1156 

1157 @property 

1158 def digital_signature(self) -> bool: 

1159 return self._digital_signature 

1160 

1161 @property 

1162 def content_commitment(self) -> bool: 

1163 return self._content_commitment 

1164 

1165 @property 

1166 def key_encipherment(self) -> bool: 

1167 return self._key_encipherment 

1168 

1169 @property 

1170 def data_encipherment(self) -> bool: 

1171 return self._data_encipherment 

1172 

1173 @property 

1174 def key_agreement(self) -> bool: 

1175 return self._key_agreement 

1176 

1177 @property 

1178 def key_cert_sign(self) -> bool: 

1179 return self._key_cert_sign 

1180 

1181 @property 

1182 def crl_sign(self) -> bool: 

1183 return self._crl_sign 

1184 

1185 @property 

1186 def encipher_only(self) -> bool: 

1187 if not self.key_agreement: 

1188 raise ValueError( 

1189 "encipher_only is undefined unless key_agreement is true" 

1190 ) 

1191 else: 

1192 return self._encipher_only 

1193 

1194 @property 

1195 def decipher_only(self) -> bool: 

1196 if not self.key_agreement: 

1197 raise ValueError( 

1198 "decipher_only is undefined unless key_agreement is true" 

1199 ) 

1200 else: 

1201 return self._decipher_only 

1202 

1203 def __repr__(self) -> str: 

1204 try: 

1205 encipher_only = self.encipher_only 

1206 decipher_only = self.decipher_only 

1207 except ValueError: 

1208 # Users found None confusing because even though encipher/decipher 

1209 # have no meaning unless key_agreement is true, to construct an 

1210 # instance of the class you still need to pass False. 

1211 encipher_only = False 

1212 decipher_only = False 

1213 

1214 return ( 

1215 "<KeyUsage(digital_signature={0.digital_signature}, " 

1216 "content_commitment={0.content_commitment}, " 

1217 "key_encipherment={0.key_encipherment}, " 

1218 "data_encipherment={0.data_encipherment}, " 

1219 "key_agreement={0.key_agreement}, " 

1220 "key_cert_sign={0.key_cert_sign}, crl_sign={0.crl_sign}, " 

1221 "encipher_only={1}, decipher_only={2})>" 

1222 ).format(self, encipher_only, decipher_only) 

1223 

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

1225 if not isinstance(other, KeyUsage): 

1226 return NotImplemented 

1227 

1228 return ( 

1229 self.digital_signature == other.digital_signature 

1230 and self.content_commitment == other.content_commitment 

1231 and self.key_encipherment == other.key_encipherment 

1232 and self.data_encipherment == other.data_encipherment 

1233 and self.key_agreement == other.key_agreement 

1234 and self.key_cert_sign == other.key_cert_sign 

1235 and self.crl_sign == other.crl_sign 

1236 and self._encipher_only == other._encipher_only 

1237 and self._decipher_only == other._decipher_only 

1238 ) 

1239 

1240 def __hash__(self) -> int: 

1241 return hash( 

1242 ( 

1243 self.digital_signature, 

1244 self.content_commitment, 

1245 self.key_encipherment, 

1246 self.data_encipherment, 

1247 self.key_agreement, 

1248 self.key_cert_sign, 

1249 self.crl_sign, 

1250 self._encipher_only, 

1251 self._decipher_only, 

1252 ) 

1253 ) 

1254 

1255 def public_bytes(self) -> bytes: 

1256 return rust_x509.encode_extension_value(self) 

1257 

1258 

1259class NameConstraints(ExtensionType): 

1260 oid = ExtensionOID.NAME_CONSTRAINTS 

1261 

1262 def __init__( 

1263 self, 

1264 permitted_subtrees: typing.Optional[typing.Iterable[GeneralName]], 

1265 excluded_subtrees: typing.Optional[typing.Iterable[GeneralName]], 

1266 ) -> None: 

1267 if permitted_subtrees is not None: 

1268 permitted_subtrees = list(permitted_subtrees) 

1269 if not permitted_subtrees: 

1270 raise ValueError( 

1271 "permitted_subtrees must be a non-empty list or None" 

1272 ) 

1273 if not all(isinstance(x, GeneralName) for x in permitted_subtrees): 

1274 raise TypeError( 

1275 "permitted_subtrees must be a list of GeneralName objects " 

1276 "or None" 

1277 ) 

1278 

1279 self._validate_tree(permitted_subtrees) 

1280 

1281 if excluded_subtrees is not None: 

1282 excluded_subtrees = list(excluded_subtrees) 

1283 if not excluded_subtrees: 

1284 raise ValueError( 

1285 "excluded_subtrees must be a non-empty list or None" 

1286 ) 

1287 if not all(isinstance(x, GeneralName) for x in excluded_subtrees): 

1288 raise TypeError( 

1289 "excluded_subtrees must be a list of GeneralName objects " 

1290 "or None" 

1291 ) 

1292 

1293 self._validate_tree(excluded_subtrees) 

1294 

1295 if permitted_subtrees is None and excluded_subtrees is None: 

1296 raise ValueError( 

1297 "At least one of permitted_subtrees and excluded_subtrees " 

1298 "must not be None" 

1299 ) 

1300 

1301 self._permitted_subtrees = permitted_subtrees 

1302 self._excluded_subtrees = excluded_subtrees 

1303 

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

1305 if not isinstance(other, NameConstraints): 

1306 return NotImplemented 

1307 

1308 return ( 

1309 self.excluded_subtrees == other.excluded_subtrees 

1310 and self.permitted_subtrees == other.permitted_subtrees 

1311 ) 

1312 

1313 def _validate_tree(self, tree: typing.Iterable[GeneralName]) -> None: 

1314 self._validate_ip_name(tree) 

1315 self._validate_dns_name(tree) 

1316 

1317 def _validate_ip_name(self, tree: typing.Iterable[GeneralName]) -> None: 

1318 if any( 

1319 isinstance(name, IPAddress) 

1320 and not isinstance( 

1321 name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network) 

1322 ) 

1323 for name in tree 

1324 ): 

1325 raise TypeError( 

1326 "IPAddress name constraints must be an IPv4Network or" 

1327 " IPv6Network object" 

1328 ) 

1329 

1330 def _validate_dns_name(self, tree: typing.Iterable[GeneralName]) -> None: 

1331 if any( 

1332 isinstance(name, DNSName) and "*" in name.value for name in tree 

1333 ): 

1334 raise ValueError( 

1335 "DNSName name constraints must not contain the '*' wildcard" 

1336 " character" 

1337 ) 

1338 

1339 def __repr__(self) -> str: 

1340 return ( 

1341 "<NameConstraints(permitted_subtrees={0.permitted_subtrees}, " 

1342 "excluded_subtrees={0.excluded_subtrees})>".format(self) 

1343 ) 

1344 

1345 def __hash__(self) -> int: 

1346 if self.permitted_subtrees is not None: 

1347 ps: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple( 

1348 self.permitted_subtrees 

1349 ) 

1350 else: 

1351 ps = None 

1352 

1353 if self.excluded_subtrees is not None: 

1354 es: typing.Optional[typing.Tuple[GeneralName, ...]] = tuple( 

1355 self.excluded_subtrees 

1356 ) 

1357 else: 

1358 es = None 

1359 

1360 return hash((ps, es)) 

1361 

1362 @property 

1363 def permitted_subtrees( 

1364 self, 

1365 ) -> typing.Optional[typing.List[GeneralName]]: 

1366 return self._permitted_subtrees 

1367 

1368 @property 

1369 def excluded_subtrees( 

1370 self, 

1371 ) -> typing.Optional[typing.List[GeneralName]]: 

1372 return self._excluded_subtrees 

1373 

1374 def public_bytes(self) -> bytes: 

1375 return rust_x509.encode_extension_value(self) 

1376 

1377 

1378class Extension(typing.Generic[ExtensionTypeVar]): 

1379 def __init__( 

1380 self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar 

1381 ) -> None: 

1382 if not isinstance(oid, ObjectIdentifier): 

1383 raise TypeError( 

1384 "oid argument must be an ObjectIdentifier instance." 

1385 ) 

1386 

1387 if not isinstance(critical, bool): 

1388 raise TypeError("critical must be a boolean value") 

1389 

1390 self._oid = oid 

1391 self._critical = critical 

1392 self._value = value 

1393 

1394 @property 

1395 def oid(self) -> ObjectIdentifier: 

1396 return self._oid 

1397 

1398 @property 

1399 def critical(self) -> bool: 

1400 return self._critical 

1401 

1402 @property 

1403 def value(self) -> ExtensionTypeVar: 

1404 return self._value 

1405 

1406 def __repr__(self) -> str: 

1407 return ( 

1408 "<Extension(oid={0.oid}, critical={0.critical}, " 

1409 "value={0.value})>" 

1410 ).format(self) 

1411 

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

1413 if not isinstance(other, Extension): 

1414 return NotImplemented 

1415 

1416 return ( 

1417 self.oid == other.oid 

1418 and self.critical == other.critical 

1419 and self.value == other.value 

1420 ) 

1421 

1422 def __hash__(self) -> int: 

1423 return hash((self.oid, self.critical, self.value)) 

1424 

1425 

1426class GeneralNames: 

1427 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: 

1428 general_names = list(general_names) 

1429 if not all(isinstance(x, GeneralName) for x in general_names): 

1430 raise TypeError( 

1431 "Every item in the general_names list must be an " 

1432 "object conforming to the GeneralName interface" 

1433 ) 

1434 

1435 self._general_names = general_names 

1436 

1437 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") 

1438 

1439 @typing.overload 

1440 def get_values_for_type( 

1441 self, 

1442 type: typing.Union[ 

1443 typing.Type[DNSName], 

1444 typing.Type[UniformResourceIdentifier], 

1445 typing.Type[RFC822Name], 

1446 ], 

1447 ) -> typing.List[str]: 

1448 ... 

1449 

1450 @typing.overload 

1451 def get_values_for_type( 

1452 self, 

1453 type: typing.Type[DirectoryName], 

1454 ) -> typing.List[Name]: 

1455 ... 

1456 

1457 @typing.overload 

1458 def get_values_for_type( 

1459 self, 

1460 type: typing.Type[RegisteredID], 

1461 ) -> typing.List[ObjectIdentifier]: 

1462 ... 

1463 

1464 @typing.overload 

1465 def get_values_for_type( 

1466 self, type: typing.Type[IPAddress] 

1467 ) -> typing.List[_IPAddressTypes]: 

1468 ... 

1469 

1470 @typing.overload 

1471 def get_values_for_type( 

1472 self, type: typing.Type[OtherName] 

1473 ) -> typing.List[OtherName]: 

1474 ... 

1475 

1476 def get_values_for_type( 

1477 self, 

1478 type: typing.Union[ 

1479 typing.Type[DNSName], 

1480 typing.Type[DirectoryName], 

1481 typing.Type[IPAddress], 

1482 typing.Type[OtherName], 

1483 typing.Type[RFC822Name], 

1484 typing.Type[RegisteredID], 

1485 typing.Type[UniformResourceIdentifier], 

1486 ], 

1487 ) -> typing.Union[ 

1488 typing.List[_IPAddressTypes], 

1489 typing.List[str], 

1490 typing.List[OtherName], 

1491 typing.List[Name], 

1492 typing.List[ObjectIdentifier], 

1493 ]: 

1494 # Return the value of each GeneralName, except for OtherName instances 

1495 # which we return directly because it has two important properties not 

1496 # just one value. 

1497 objs = (i for i in self if isinstance(i, type)) 

1498 if type != OtherName: 

1499 return [i.value for i in objs] 

1500 return list(objs) 

1501 

1502 def __repr__(self) -> str: 

1503 return f"<GeneralNames({self._general_names})>" 

1504 

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

1506 if not isinstance(other, GeneralNames): 

1507 return NotImplemented 

1508 

1509 return self._general_names == other._general_names 

1510 

1511 def __hash__(self) -> int: 

1512 return hash(tuple(self._general_names)) 

1513 

1514 

1515class SubjectAlternativeName(ExtensionType): 

1516 oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME 

1517 

1518 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: 

1519 self._general_names = GeneralNames(general_names) 

1520 

1521 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") 

1522 

1523 @typing.overload 

1524 def get_values_for_type( 

1525 self, 

1526 type: typing.Union[ 

1527 typing.Type[DNSName], 

1528 typing.Type[UniformResourceIdentifier], 

1529 typing.Type[RFC822Name], 

1530 ], 

1531 ) -> typing.List[str]: 

1532 ... 

1533 

1534 @typing.overload 

1535 def get_values_for_type( 

1536 self, 

1537 type: typing.Type[DirectoryName], 

1538 ) -> typing.List[Name]: 

1539 ... 

1540 

1541 @typing.overload 

1542 def get_values_for_type( 

1543 self, 

1544 type: typing.Type[RegisteredID], 

1545 ) -> typing.List[ObjectIdentifier]: 

1546 ... 

1547 

1548 @typing.overload 

1549 def get_values_for_type( 

1550 self, type: typing.Type[IPAddress] 

1551 ) -> typing.List[_IPAddressTypes]: 

1552 ... 

1553 

1554 @typing.overload 

1555 def get_values_for_type( 

1556 self, type: typing.Type[OtherName] 

1557 ) -> typing.List[OtherName]: 

1558 ... 

1559 

1560 def get_values_for_type( 

1561 self, 

1562 type: typing.Union[ 

1563 typing.Type[DNSName], 

1564 typing.Type[DirectoryName], 

1565 typing.Type[IPAddress], 

1566 typing.Type[OtherName], 

1567 typing.Type[RFC822Name], 

1568 typing.Type[RegisteredID], 

1569 typing.Type[UniformResourceIdentifier], 

1570 ], 

1571 ) -> typing.Union[ 

1572 typing.List[_IPAddressTypes], 

1573 typing.List[str], 

1574 typing.List[OtherName], 

1575 typing.List[Name], 

1576 typing.List[ObjectIdentifier], 

1577 ]: 

1578 return self._general_names.get_values_for_type(type) 

1579 

1580 def __repr__(self) -> str: 

1581 return f"<SubjectAlternativeName({self._general_names})>" 

1582 

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

1584 if not isinstance(other, SubjectAlternativeName): 

1585 return NotImplemented 

1586 

1587 return self._general_names == other._general_names 

1588 

1589 def __hash__(self) -> int: 

1590 return hash(self._general_names) 

1591 

1592 def public_bytes(self) -> bytes: 

1593 return rust_x509.encode_extension_value(self) 

1594 

1595 

1596class IssuerAlternativeName(ExtensionType): 

1597 oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME 

1598 

1599 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: 

1600 self._general_names = GeneralNames(general_names) 

1601 

1602 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") 

1603 

1604 @typing.overload 

1605 def get_values_for_type( 

1606 self, 

1607 type: typing.Union[ 

1608 typing.Type[DNSName], 

1609 typing.Type[UniformResourceIdentifier], 

1610 typing.Type[RFC822Name], 

1611 ], 

1612 ) -> typing.List[str]: 

1613 ... 

1614 

1615 @typing.overload 

1616 def get_values_for_type( 

1617 self, 

1618 type: typing.Type[DirectoryName], 

1619 ) -> typing.List[Name]: 

1620 ... 

1621 

1622 @typing.overload 

1623 def get_values_for_type( 

1624 self, 

1625 type: typing.Type[RegisteredID], 

1626 ) -> typing.List[ObjectIdentifier]: 

1627 ... 

1628 

1629 @typing.overload 

1630 def get_values_for_type( 

1631 self, type: typing.Type[IPAddress] 

1632 ) -> typing.List[_IPAddressTypes]: 

1633 ... 

1634 

1635 @typing.overload 

1636 def get_values_for_type( 

1637 self, type: typing.Type[OtherName] 

1638 ) -> typing.List[OtherName]: 

1639 ... 

1640 

1641 def get_values_for_type( 

1642 self, 

1643 type: typing.Union[ 

1644 typing.Type[DNSName], 

1645 typing.Type[DirectoryName], 

1646 typing.Type[IPAddress], 

1647 typing.Type[OtherName], 

1648 typing.Type[RFC822Name], 

1649 typing.Type[RegisteredID], 

1650 typing.Type[UniformResourceIdentifier], 

1651 ], 

1652 ) -> typing.Union[ 

1653 typing.List[_IPAddressTypes], 

1654 typing.List[str], 

1655 typing.List[OtherName], 

1656 typing.List[Name], 

1657 typing.List[ObjectIdentifier], 

1658 ]: 

1659 return self._general_names.get_values_for_type(type) 

1660 

1661 def __repr__(self) -> str: 

1662 return f"<IssuerAlternativeName({self._general_names})>" 

1663 

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

1665 if not isinstance(other, IssuerAlternativeName): 

1666 return NotImplemented 

1667 

1668 return self._general_names == other._general_names 

1669 

1670 def __hash__(self) -> int: 

1671 return hash(self._general_names) 

1672 

1673 def public_bytes(self) -> bytes: 

1674 return rust_x509.encode_extension_value(self) 

1675 

1676 

1677class CertificateIssuer(ExtensionType): 

1678 oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER 

1679 

1680 def __init__(self, general_names: typing.Iterable[GeneralName]) -> None: 

1681 self._general_names = GeneralNames(general_names) 

1682 

1683 __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") 

1684 

1685 @typing.overload 

1686 def get_values_for_type( 

1687 self, 

1688 type: typing.Union[ 

1689 typing.Type[DNSName], 

1690 typing.Type[UniformResourceIdentifier], 

1691 typing.Type[RFC822Name], 

1692 ], 

1693 ) -> typing.List[str]: 

1694 ... 

1695 

1696 @typing.overload 

1697 def get_values_for_type( 

1698 self, 

1699 type: typing.Type[DirectoryName], 

1700 ) -> typing.List[Name]: 

1701 ... 

1702 

1703 @typing.overload 

1704 def get_values_for_type( 

1705 self, 

1706 type: typing.Type[RegisteredID], 

1707 ) -> typing.List[ObjectIdentifier]: 

1708 ... 

1709 

1710 @typing.overload 

1711 def get_values_for_type( 

1712 self, type: typing.Type[IPAddress] 

1713 ) -> typing.List[_IPAddressTypes]: 

1714 ... 

1715 

1716 @typing.overload 

1717 def get_values_for_type( 

1718 self, type: typing.Type[OtherName] 

1719 ) -> typing.List[OtherName]: 

1720 ... 

1721 

1722 def get_values_for_type( 

1723 self, 

1724 type: typing.Union[ 

1725 typing.Type[DNSName], 

1726 typing.Type[DirectoryName], 

1727 typing.Type[IPAddress], 

1728 typing.Type[OtherName], 

1729 typing.Type[RFC822Name], 

1730 typing.Type[RegisteredID], 

1731 typing.Type[UniformResourceIdentifier], 

1732 ], 

1733 ) -> typing.Union[ 

1734 typing.List[_IPAddressTypes], 

1735 typing.List[str], 

1736 typing.List[OtherName], 

1737 typing.List[Name], 

1738 typing.List[ObjectIdentifier], 

1739 ]: 

1740 return self._general_names.get_values_for_type(type) 

1741 

1742 def __repr__(self) -> str: 

1743 return f"<CertificateIssuer({self._general_names})>" 

1744 

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

1746 if not isinstance(other, CertificateIssuer): 

1747 return NotImplemented 

1748 

1749 return self._general_names == other._general_names 

1750 

1751 def __hash__(self) -> int: 

1752 return hash(self._general_names) 

1753 

1754 def public_bytes(self) -> bytes: 

1755 return rust_x509.encode_extension_value(self) 

1756 

1757 

1758class CRLReason(ExtensionType): 

1759 oid = CRLEntryExtensionOID.CRL_REASON 

1760 

1761 def __init__(self, reason: ReasonFlags) -> None: 

1762 if not isinstance(reason, ReasonFlags): 

1763 raise TypeError("reason must be an element from ReasonFlags") 

1764 

1765 self._reason = reason 

1766 

1767 def __repr__(self) -> str: 

1768 return f"<CRLReason(reason={self._reason})>" 

1769 

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

1771 if not isinstance(other, CRLReason): 

1772 return NotImplemented 

1773 

1774 return self.reason == other.reason 

1775 

1776 def __hash__(self) -> int: 

1777 return hash(self.reason) 

1778 

1779 @property 

1780 def reason(self) -> ReasonFlags: 

1781 return self._reason 

1782 

1783 def public_bytes(self) -> bytes: 

1784 return rust_x509.encode_extension_value(self) 

1785 

1786 

1787class InvalidityDate(ExtensionType): 

1788 oid = CRLEntryExtensionOID.INVALIDITY_DATE 

1789 

1790 def __init__(self, invalidity_date: datetime.datetime) -> None: 

1791 if not isinstance(invalidity_date, datetime.datetime): 

1792 raise TypeError("invalidity_date must be a datetime.datetime") 

1793 

1794 self._invalidity_date = invalidity_date 

1795 

1796 def __repr__(self) -> str: 

1797 return "<InvalidityDate(invalidity_date={})>".format( 

1798 self._invalidity_date 

1799 ) 

1800 

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

1802 if not isinstance(other, InvalidityDate): 

1803 return NotImplemented 

1804 

1805 return self.invalidity_date == other.invalidity_date 

1806 

1807 def __hash__(self) -> int: 

1808 return hash(self.invalidity_date) 

1809 

1810 @property 

1811 def invalidity_date(self) -> datetime.datetime: 

1812 return self._invalidity_date 

1813 

1814 def public_bytes(self) -> bytes: 

1815 return rust_x509.encode_extension_value(self) 

1816 

1817 

1818class PrecertificateSignedCertificateTimestamps(ExtensionType): 

1819 oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS 

1820 

1821 def __init__( 

1822 self, 

1823 signed_certificate_timestamps: typing.Iterable[ 

1824 SignedCertificateTimestamp 

1825 ], 

1826 ) -> None: 

1827 signed_certificate_timestamps = list(signed_certificate_timestamps) 

1828 if not all( 

1829 isinstance(sct, SignedCertificateTimestamp) 

1830 for sct in signed_certificate_timestamps 

1831 ): 

1832 raise TypeError( 

1833 "Every item in the signed_certificate_timestamps list must be " 

1834 "a SignedCertificateTimestamp" 

1835 ) 

1836 self._signed_certificate_timestamps = signed_certificate_timestamps 

1837 

1838 __len__, __iter__, __getitem__ = _make_sequence_methods( 

1839 "_signed_certificate_timestamps" 

1840 ) 

1841 

1842 def __repr__(self) -> str: 

1843 return "<PrecertificateSignedCertificateTimestamps({})>".format( 

1844 list(self) 

1845 ) 

1846 

1847 def __hash__(self) -> int: 

1848 return hash(tuple(self._signed_certificate_timestamps)) 

1849 

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

1851 if not isinstance(other, PrecertificateSignedCertificateTimestamps): 

1852 return NotImplemented 

1853 

1854 return ( 

1855 self._signed_certificate_timestamps 

1856 == other._signed_certificate_timestamps 

1857 ) 

1858 

1859 def public_bytes(self) -> bytes: 

1860 return rust_x509.encode_extension_value(self) 

1861 

1862 

1863class SignedCertificateTimestamps(ExtensionType): 

1864 oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS 

1865 

1866 def __init__( 

1867 self, 

1868 signed_certificate_timestamps: typing.Iterable[ 

1869 SignedCertificateTimestamp 

1870 ], 

1871 ) -> None: 

1872 signed_certificate_timestamps = list(signed_certificate_timestamps) 

1873 if not all( 

1874 isinstance(sct, SignedCertificateTimestamp) 

1875 for sct in signed_certificate_timestamps 

1876 ): 

1877 raise TypeError( 

1878 "Every item in the signed_certificate_timestamps list must be " 

1879 "a SignedCertificateTimestamp" 

1880 ) 

1881 self._signed_certificate_timestamps = signed_certificate_timestamps 

1882 

1883 __len__, __iter__, __getitem__ = _make_sequence_methods( 

1884 "_signed_certificate_timestamps" 

1885 ) 

1886 

1887 def __repr__(self) -> str: 

1888 return f"<SignedCertificateTimestamps({list(self)})>" 

1889 

1890 def __hash__(self) -> int: 

1891 return hash(tuple(self._signed_certificate_timestamps)) 

1892 

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

1894 if not isinstance(other, SignedCertificateTimestamps): 

1895 return NotImplemented 

1896 

1897 return ( 

1898 self._signed_certificate_timestamps 

1899 == other._signed_certificate_timestamps 

1900 ) 

1901 

1902 def public_bytes(self) -> bytes: 

1903 return rust_x509.encode_extension_value(self) 

1904 

1905 

1906class OCSPNonce(ExtensionType): 

1907 oid = OCSPExtensionOID.NONCE 

1908 

1909 def __init__(self, nonce: bytes) -> None: 

1910 if not isinstance(nonce, bytes): 

1911 raise TypeError("nonce must be bytes") 

1912 

1913 self._nonce = nonce 

1914 

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

1916 if not isinstance(other, OCSPNonce): 

1917 return NotImplemented 

1918 

1919 return self.nonce == other.nonce 

1920 

1921 def __hash__(self) -> int: 

1922 return hash(self.nonce) 

1923 

1924 def __repr__(self) -> str: 

1925 return f"<OCSPNonce(nonce={self.nonce!r})>" 

1926 

1927 @property 

1928 def nonce(self) -> bytes: 

1929 return self._nonce 

1930 

1931 def public_bytes(self) -> bytes: 

1932 return rust_x509.encode_extension_value(self) 

1933 

1934 

1935class IssuingDistributionPoint(ExtensionType): 

1936 oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT 

1937 

1938 def __init__( 

1939 self, 

1940 full_name: typing.Optional[typing.Iterable[GeneralName]], 

1941 relative_name: typing.Optional[RelativeDistinguishedName], 

1942 only_contains_user_certs: bool, 

1943 only_contains_ca_certs: bool, 

1944 only_some_reasons: typing.Optional[typing.FrozenSet[ReasonFlags]], 

1945 indirect_crl: bool, 

1946 only_contains_attribute_certs: bool, 

1947 ) -> None: 

1948 if full_name is not None: 

1949 full_name = list(full_name) 

1950 

1951 if only_some_reasons and ( 

1952 not isinstance(only_some_reasons, frozenset) 

1953 or not all(isinstance(x, ReasonFlags) for x in only_some_reasons) 

1954 ): 

1955 raise TypeError( 

1956 "only_some_reasons must be None or frozenset of ReasonFlags" 

1957 ) 

1958 

1959 if only_some_reasons and ( 

1960 ReasonFlags.unspecified in only_some_reasons 

1961 or ReasonFlags.remove_from_crl in only_some_reasons 

1962 ): 

1963 raise ValueError( 

1964 "unspecified and remove_from_crl are not valid reasons in an " 

1965 "IssuingDistributionPoint" 

1966 ) 

1967 

1968 if not ( 

1969 isinstance(only_contains_user_certs, bool) 

1970 and isinstance(only_contains_ca_certs, bool) 

1971 and isinstance(indirect_crl, bool) 

1972 and isinstance(only_contains_attribute_certs, bool) 

1973 ): 

1974 raise TypeError( 

1975 "only_contains_user_certs, only_contains_ca_certs, " 

1976 "indirect_crl and only_contains_attribute_certs " 

1977 "must all be boolean." 

1978 ) 

1979 

1980 crl_constraints = [ 

1981 only_contains_user_certs, 

1982 only_contains_ca_certs, 

1983 indirect_crl, 

1984 only_contains_attribute_certs, 

1985 ] 

1986 

1987 if len([x for x in crl_constraints if x]) > 1: 

1988 raise ValueError( 

1989 "Only one of the following can be set to True: " 

1990 "only_contains_user_certs, only_contains_ca_certs, " 

1991 "indirect_crl, only_contains_attribute_certs" 

1992 ) 

1993 

1994 if not any( 

1995 [ 

1996 only_contains_user_certs, 

1997 only_contains_ca_certs, 

1998 indirect_crl, 

1999 only_contains_attribute_certs, 

2000 full_name, 

2001 relative_name, 

2002 only_some_reasons, 

2003 ] 

2004 ): 

2005 raise ValueError( 

2006 "Cannot create empty extension: " 

2007 "if only_contains_user_certs, only_contains_ca_certs, " 

2008 "indirect_crl, and only_contains_attribute_certs are all False" 

2009 ", then either full_name, relative_name, or only_some_reasons " 

2010 "must have a value." 

2011 ) 

2012 

2013 self._only_contains_user_certs = only_contains_user_certs 

2014 self._only_contains_ca_certs = only_contains_ca_certs 

2015 self._indirect_crl = indirect_crl 

2016 self._only_contains_attribute_certs = only_contains_attribute_certs 

2017 self._only_some_reasons = only_some_reasons 

2018 self._full_name = full_name 

2019 self._relative_name = relative_name 

2020 

2021 def __repr__(self) -> str: 

2022 return ( 

2023 "<IssuingDistributionPoint(full_name={0.full_name}, " 

2024 "relative_name={0.relative_name}, " 

2025 "only_contains_user_certs={0.only_contains_user_certs}, " 

2026 "only_contains_ca_certs={0.only_contains_ca_certs}, " 

2027 "only_some_reasons={0.only_some_reasons}, " 

2028 "indirect_crl={0.indirect_crl}, " 

2029 "only_contains_attribute_certs=" 

2030 "{0.only_contains_attribute_certs})>".format(self) 

2031 ) 

2032 

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

2034 if not isinstance(other, IssuingDistributionPoint): 

2035 return NotImplemented 

2036 

2037 return ( 

2038 self.full_name == other.full_name 

2039 and self.relative_name == other.relative_name 

2040 and self.only_contains_user_certs == other.only_contains_user_certs 

2041 and self.only_contains_ca_certs == other.only_contains_ca_certs 

2042 and self.only_some_reasons == other.only_some_reasons 

2043 and self.indirect_crl == other.indirect_crl 

2044 and self.only_contains_attribute_certs 

2045 == other.only_contains_attribute_certs 

2046 ) 

2047 

2048 def __hash__(self) -> int: 

2049 return hash( 

2050 ( 

2051 self.full_name, 

2052 self.relative_name, 

2053 self.only_contains_user_certs, 

2054 self.only_contains_ca_certs, 

2055 self.only_some_reasons, 

2056 self.indirect_crl, 

2057 self.only_contains_attribute_certs, 

2058 ) 

2059 ) 

2060 

2061 @property 

2062 def full_name(self) -> typing.Optional[typing.List[GeneralName]]: 

2063 return self._full_name 

2064 

2065 @property 

2066 def relative_name(self) -> typing.Optional[RelativeDistinguishedName]: 

2067 return self._relative_name 

2068 

2069 @property 

2070 def only_contains_user_certs(self) -> bool: 

2071 return self._only_contains_user_certs 

2072 

2073 @property 

2074 def only_contains_ca_certs(self) -> bool: 

2075 return self._only_contains_ca_certs 

2076 

2077 @property 

2078 def only_some_reasons( 

2079 self, 

2080 ) -> typing.Optional[typing.FrozenSet[ReasonFlags]]: 

2081 return self._only_some_reasons 

2082 

2083 @property 

2084 def indirect_crl(self) -> bool: 

2085 return self._indirect_crl 

2086 

2087 @property 

2088 def only_contains_attribute_certs(self) -> bool: 

2089 return self._only_contains_attribute_certs 

2090 

2091 def public_bytes(self) -> bytes: 

2092 return rust_x509.encode_extension_value(self) 

2093 

2094 

2095class UnrecognizedExtension(ExtensionType): 

2096 def __init__(self, oid: ObjectIdentifier, value: bytes) -> None: 

2097 if not isinstance(oid, ObjectIdentifier): 

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

2099 self._oid = oid 

2100 self._value = value 

2101 

2102 @property 

2103 def oid(self) -> ObjectIdentifier: # type: ignore[override] 

2104 return self._oid 

2105 

2106 @property 

2107 def value(self) -> bytes: 

2108 return self._value 

2109 

2110 def __repr__(self) -> str: 

2111 return ( 

2112 "<UnrecognizedExtension(oid={0.oid}, " 

2113 "value={0.value!r})>".format(self) 

2114 ) 

2115 

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

2117 if not isinstance(other, UnrecognizedExtension): 

2118 return NotImplemented 

2119 

2120 return self.oid == other.oid and self.value == other.value 

2121 

2122 def __hash__(self) -> int: 

2123 return hash((self.oid, self.value)) 

2124 

2125 def public_bytes(self) -> bytes: 

2126 return self.value