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

1038 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:50 +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 

5from __future__ import annotations 

6 

7import abc 

8import datetime 

9import hashlib 

10import ipaddress 

11import typing 

12 

13from cryptography import utils 

14from cryptography.hazmat.bindings._rust import asn1 

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

16from cryptography.hazmat.primitives import constant_time, serialization 

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

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

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

20 CertificateIssuerPublicKeyTypes, 

21 CertificatePublicKeyTypes, 

22) 

23from cryptography.x509.certificate_transparency import ( 

24 SignedCertificateTimestamp, 

25) 

26from cryptography.x509.general_name import ( 

27 DirectoryName, 

28 DNSName, 

29 GeneralName, 

30 IPAddress, 

31 OtherName, 

32 RegisteredID, 

33 RFC822Name, 

34 UniformResourceIdentifier, 

35 _IPAddressTypes, 

36) 

37from cryptography.x509.name import Name, RelativeDistinguishedName 

38from cryptography.x509.oid import ( 

39 CRLEntryExtensionOID, 

40 ExtensionOID, 

41 ObjectIdentifier, 

42 OCSPExtensionOID, 

43) 

44 

45ExtensionTypeVar = typing.TypeVar( 

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

47) 

48 

49 

50def _key_identifier_from_public_key( 

51 public_key: CertificatePublicKeyTypes, 

52) -> bytes: 

53 if isinstance(public_key, RSAPublicKey): 

54 data = public_key.public_bytes( 

55 serialization.Encoding.DER, 

56 serialization.PublicFormat.PKCS1, 

57 ) 

58 elif isinstance(public_key, EllipticCurvePublicKey): 

59 data = public_key.public_bytes( 

60 serialization.Encoding.X962, 

61 serialization.PublicFormat.UncompressedPoint, 

62 ) 

63 else: 

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

65 serialized = public_key.public_bytes( 

66 serialization.Encoding.DER, 

67 serialization.PublicFormat.SubjectPublicKeyInfo, 

68 ) 

69 data = asn1.parse_spki_for_data(serialized) 

70 

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

72 

73 

74def _make_sequence_methods(field_name: str): 

75 def len_method(self) -> int: 

76 return len(getattr(self, field_name)) 

77 

78 def iter_method(self): 

79 return iter(getattr(self, field_name)) 

80 

81 def getitem_method(self, idx): 

82 return getattr(self, field_name)[idx] 

83 

84 return len_method, iter_method, getitem_method 

85 

86 

87class DuplicateExtension(Exception): 

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

89 super().__init__(msg) 

90 self.oid = oid 

91 

92 

93class ExtensionNotFound(Exception): 

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

95 super().__init__(msg) 

96 self.oid = oid 

97 

98 

99class ExtensionType(metaclass=abc.ABCMeta): 

100 oid: typing.ClassVar[ObjectIdentifier] 

101 

102 def public_bytes(self) -> bytes: 

103 """ 

104 Serializes the extension type to DER. 

105 """ 

106 raise NotImplementedError( 

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

108 self 

109 ) 

110 ) 

111 

112 

113class Extensions: 

114 def __init__( 

115 self, extensions: typing.Iterable[Extension[ExtensionType]] 

116 ) -> None: 

117 self._extensions = list(extensions) 

118 

119 def get_extension_for_oid( 

120 self, oid: ObjectIdentifier 

121 ) -> Extension[ExtensionType]: 

122 for ext in self: 

123 if ext.oid == oid: 

124 return ext 

125 

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

127 

128 def get_extension_for_class( 

129 self, extclass: typing.Type[ExtensionTypeVar] 

130 ) -> Extension[ExtensionTypeVar]: 

131 if extclass is UnrecognizedExtension: 

132 raise TypeError( 

133 "UnrecognizedExtension can't be used with " 

134 "get_extension_for_class because more than one instance of the" 

135 " class may be present." 

136 ) 

137 

138 for ext in self: 

139 if isinstance(ext.value, extclass): 

140 return ext 

141 

142 raise ExtensionNotFound( 

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

144 ) 

145 

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

147 

148 def __repr__(self) -> str: 

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

150 

151 

152class CRLNumber(ExtensionType): 

153 oid = ExtensionOID.CRL_NUMBER 

154 

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

156 if not isinstance(crl_number, int): 

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

158 

159 self._crl_number = crl_number 

160 

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

162 if not isinstance(other, CRLNumber): 

163 return NotImplemented 

164 

165 return self.crl_number == other.crl_number 

166 

167 def __hash__(self) -> int: 

168 return hash(self.crl_number) 

169 

170 def __repr__(self) -> str: 

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

172 

173 @property 

174 def crl_number(self) -> int: 

175 return self._crl_number 

176 

177 def public_bytes(self) -> bytes: 

178 return rust_x509.encode_extension_value(self) 

179 

180 

181class AuthorityKeyIdentifier(ExtensionType): 

182 oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER 

183 

184 def __init__( 

185 self, 

186 key_identifier: typing.Optional[bytes], 

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

188 authority_cert_serial_number: typing.Optional[int], 

189 ) -> None: 

190 if (authority_cert_issuer is None) != ( 

191 authority_cert_serial_number is None 

192 ): 

193 raise ValueError( 

194 "authority_cert_issuer and authority_cert_serial_number " 

195 "must both be present or both None" 

196 ) 

197 

198 if authority_cert_issuer is not None: 

199 authority_cert_issuer = list(authority_cert_issuer) 

200 if not all( 

201 isinstance(x, GeneralName) for x in authority_cert_issuer 

202 ): 

203 raise TypeError( 

204 "authority_cert_issuer must be a list of GeneralName " 

205 "objects" 

206 ) 

207 

208 if authority_cert_serial_number is not None and not isinstance( 

209 authority_cert_serial_number, int 

210 ): 

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

212 

213 self._key_identifier = key_identifier 

214 self._authority_cert_issuer = authority_cert_issuer 

215 self._authority_cert_serial_number = authority_cert_serial_number 

216 

217 # This takes a subset of CertificatePublicKeyTypes because an issuer 

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

219 # asymmetry that requires typing users to explicitly 

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

221 # convenient. 

222 @classmethod 

223 def from_issuer_public_key( 

224 cls, public_key: CertificateIssuerPublicKeyTypes 

225 ) -> AuthorityKeyIdentifier: 

226 digest = _key_identifier_from_public_key(public_key) 

227 return cls( 

228 key_identifier=digest, 

229 authority_cert_issuer=None, 

230 authority_cert_serial_number=None, 

231 ) 

232 

233 @classmethod 

234 def from_issuer_subject_key_identifier( 

235 cls, ski: SubjectKeyIdentifier 

236 ) -> AuthorityKeyIdentifier: 

237 return cls( 

238 key_identifier=ski.digest, 

239 authority_cert_issuer=None, 

240 authority_cert_serial_number=None, 

241 ) 

242 

243 def __repr__(self) -> str: 

244 return ( 

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

246 "authority_cert_issuer={0.authority_cert_issuer}, " 

247 "authority_cert_serial_number={0.authority_cert_serial_number}" 

248 ")>".format(self) 

249 ) 

250 

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

252 if not isinstance(other, AuthorityKeyIdentifier): 

253 return NotImplemented 

254 

255 return ( 

256 self.key_identifier == other.key_identifier 

257 and self.authority_cert_issuer == other.authority_cert_issuer 

258 and self.authority_cert_serial_number 

259 == other.authority_cert_serial_number 

260 ) 

261 

262 def __hash__(self) -> int: 

263 if self.authority_cert_issuer is None: 

264 aci = None 

265 else: 

266 aci = tuple(self.authority_cert_issuer) 

267 return hash( 

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

269 ) 

270 

271 @property 

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

273 return self._key_identifier 

274 

275 @property 

276 def authority_cert_issuer( 

277 self, 

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

279 return self._authority_cert_issuer 

280 

281 @property 

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

283 return self._authority_cert_serial_number 

284 

285 def public_bytes(self) -> bytes: 

286 return rust_x509.encode_extension_value(self) 

287 

288 

289class SubjectKeyIdentifier(ExtensionType): 

290 oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER 

291 

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

293 self._digest = digest 

294 

295 @classmethod 

296 def from_public_key( 

297 cls, public_key: CertificatePublicKeyTypes 

298 ) -> SubjectKeyIdentifier: 

299 return cls(_key_identifier_from_public_key(public_key)) 

300 

301 @property 

302 def digest(self) -> bytes: 

303 return self._digest 

304 

305 @property 

306 def key_identifier(self) -> bytes: 

307 return self._digest 

308 

309 def __repr__(self) -> str: 

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

311 

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

313 if not isinstance(other, SubjectKeyIdentifier): 

314 return NotImplemented 

315 

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

317 

318 def __hash__(self) -> int: 

319 return hash(self.digest) 

320 

321 def public_bytes(self) -> bytes: 

322 return rust_x509.encode_extension_value(self) 

323 

324 

325class AuthorityInformationAccess(ExtensionType): 

326 oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS 

327 

328 def __init__( 

329 self, descriptions: typing.Iterable[AccessDescription] 

330 ) -> None: 

331 descriptions = list(descriptions) 

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

333 raise TypeError( 

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

335 "AccessDescription" 

336 ) 

337 

338 self._descriptions = descriptions 

339 

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

341 

342 def __repr__(self) -> str: 

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

344 

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

346 if not isinstance(other, AuthorityInformationAccess): 

347 return NotImplemented 

348 

349 return self._descriptions == other._descriptions 

350 

351 def __hash__(self) -> int: 

352 return hash(tuple(self._descriptions)) 

353 

354 def public_bytes(self) -> bytes: 

355 return rust_x509.encode_extension_value(self) 

356 

357 

358class SubjectInformationAccess(ExtensionType): 

359 oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS 

360 

361 def __init__( 

362 self, descriptions: typing.Iterable[AccessDescription] 

363 ) -> None: 

364 descriptions = list(descriptions) 

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

366 raise TypeError( 

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

368 "AccessDescription" 

369 ) 

370 

371 self._descriptions = descriptions 

372 

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

374 

375 def __repr__(self) -> str: 

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

377 

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

379 if not isinstance(other, SubjectInformationAccess): 

380 return NotImplemented 

381 

382 return self._descriptions == other._descriptions 

383 

384 def __hash__(self) -> int: 

385 return hash(tuple(self._descriptions)) 

386 

387 def public_bytes(self) -> bytes: 

388 return rust_x509.encode_extension_value(self) 

389 

390 

391class AccessDescription: 

392 def __init__( 

393 self, access_method: ObjectIdentifier, access_location: GeneralName 

394 ) -> None: 

395 if not isinstance(access_method, ObjectIdentifier): 

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

397 

398 if not isinstance(access_location, GeneralName): 

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

400 

401 self._access_method = access_method 

402 self._access_location = access_location 

403 

404 def __repr__(self) -> str: 

405 return ( 

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

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

408 ) 

409 

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

411 if not isinstance(other, AccessDescription): 

412 return NotImplemented 

413 

414 return ( 

415 self.access_method == other.access_method 

416 and self.access_location == other.access_location 

417 ) 

418 

419 def __hash__(self) -> int: 

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

421 

422 @property 

423 def access_method(self) -> ObjectIdentifier: 

424 return self._access_method 

425 

426 @property 

427 def access_location(self) -> GeneralName: 

428 return self._access_location 

429 

430 

431class BasicConstraints(ExtensionType): 

432 oid = ExtensionOID.BASIC_CONSTRAINTS 

433 

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

435 if not isinstance(ca, bool): 

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

437 

438 if path_length is not None and not ca: 

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

440 

441 if path_length is not None and ( 

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

443 ): 

444 raise TypeError( 

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

446 ) 

447 

448 self._ca = ca 

449 self._path_length = path_length 

450 

451 @property 

452 def ca(self) -> bool: 

453 return self._ca 

454 

455 @property 

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

457 return self._path_length 

458 

459 def __repr__(self) -> str: 

460 return ( 

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

462 ).format(self) 

463 

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

465 if not isinstance(other, BasicConstraints): 

466 return NotImplemented 

467 

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

469 

470 def __hash__(self) -> int: 

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

472 

473 def public_bytes(self) -> bytes: 

474 return rust_x509.encode_extension_value(self) 

475 

476 

477class DeltaCRLIndicator(ExtensionType): 

478 oid = ExtensionOID.DELTA_CRL_INDICATOR 

479 

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

481 if not isinstance(crl_number, int): 

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

483 

484 self._crl_number = crl_number 

485 

486 @property 

487 def crl_number(self) -> int: 

488 return self._crl_number 

489 

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

491 if not isinstance(other, DeltaCRLIndicator): 

492 return NotImplemented 

493 

494 return self.crl_number == other.crl_number 

495 

496 def __hash__(self) -> int: 

497 return hash(self.crl_number) 

498 

499 def __repr__(self) -> str: 

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

501 

502 def public_bytes(self) -> bytes: 

503 return rust_x509.encode_extension_value(self) 

504 

505 

506class CRLDistributionPoints(ExtensionType): 

507 oid = ExtensionOID.CRL_DISTRIBUTION_POINTS 

508 

509 def __init__( 

510 self, distribution_points: typing.Iterable[DistributionPoint] 

511 ) -> None: 

512 distribution_points = list(distribution_points) 

513 if not all( 

514 isinstance(x, DistributionPoint) for x in distribution_points 

515 ): 

516 raise TypeError( 

517 "distribution_points must be a list of DistributionPoint " 

518 "objects" 

519 ) 

520 

521 self._distribution_points = distribution_points 

522 

523 __len__, __iter__, __getitem__ = _make_sequence_methods( 

524 "_distribution_points" 

525 ) 

526 

527 def __repr__(self) -> str: 

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

529 

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

531 if not isinstance(other, CRLDistributionPoints): 

532 return NotImplemented 

533 

534 return self._distribution_points == other._distribution_points 

535 

536 def __hash__(self) -> int: 

537 return hash(tuple(self._distribution_points)) 

538 

539 def public_bytes(self) -> bytes: 

540 return rust_x509.encode_extension_value(self) 

541 

542 

543class FreshestCRL(ExtensionType): 

544 oid = ExtensionOID.FRESHEST_CRL 

545 

546 def __init__( 

547 self, distribution_points: typing.Iterable[DistributionPoint] 

548 ) -> None: 

549 distribution_points = list(distribution_points) 

550 if not all( 

551 isinstance(x, DistributionPoint) for x in distribution_points 

552 ): 

553 raise TypeError( 

554 "distribution_points must be a list of DistributionPoint " 

555 "objects" 

556 ) 

557 

558 self._distribution_points = distribution_points 

559 

560 __len__, __iter__, __getitem__ = _make_sequence_methods( 

561 "_distribution_points" 

562 ) 

563 

564 def __repr__(self) -> str: 

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

566 

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

568 if not isinstance(other, FreshestCRL): 

569 return NotImplemented 

570 

571 return self._distribution_points == other._distribution_points 

572 

573 def __hash__(self) -> int: 

574 return hash(tuple(self._distribution_points)) 

575 

576 def public_bytes(self) -> bytes: 

577 return rust_x509.encode_extension_value(self) 

578 

579 

580class DistributionPoint: 

581 def __init__( 

582 self, 

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

584 relative_name: typing.Optional[RelativeDistinguishedName], 

585 reasons: typing.Optional[typing.FrozenSet[ReasonFlags]], 

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

587 ) -> None: 

588 if full_name and relative_name: 

589 raise ValueError( 

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

591 "least one must be None." 

592 ) 

593 if not full_name and not relative_name and not crl_issuer: 

594 raise ValueError( 

595 "Either full_name, relative_name or crl_issuer must be " 

596 "provided." 

597 ) 

598 

599 if full_name is not None: 

600 full_name = list(full_name) 

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

602 raise TypeError( 

603 "full_name must be a list of GeneralName objects" 

604 ) 

605 

606 if relative_name: 

607 if not isinstance(relative_name, RelativeDistinguishedName): 

608 raise TypeError( 

609 "relative_name must be a RelativeDistinguishedName" 

610 ) 

611 

612 if crl_issuer is not None: 

613 crl_issuer = list(crl_issuer) 

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

615 raise TypeError( 

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

617 ) 

618 

619 if reasons and ( 

620 not isinstance(reasons, frozenset) 

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

622 ): 

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

624 

625 if reasons and ( 

626 ReasonFlags.unspecified in reasons 

627 or ReasonFlags.remove_from_crl in reasons 

628 ): 

629 raise ValueError( 

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

631 "DistributionPoint" 

632 ) 

633 

634 self._full_name = full_name 

635 self._relative_name = relative_name 

636 self._reasons = reasons 

637 self._crl_issuer = crl_issuer 

638 

639 def __repr__(self) -> str: 

640 return ( 

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

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

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

644 ) 

645 

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

647 if not isinstance(other, DistributionPoint): 

648 return NotImplemented 

649 

650 return ( 

651 self.full_name == other.full_name 

652 and self.relative_name == other.relative_name 

653 and self.reasons == other.reasons 

654 and self.crl_issuer == other.crl_issuer 

655 ) 

656 

657 def __hash__(self) -> int: 

658 if self.full_name is not None: 

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

660 self.full_name 

661 ) 

662 else: 

663 fn = None 

664 

665 if self.crl_issuer is not None: 

666 crl_issuer: typing.Optional[ 

667 typing.Tuple[GeneralName, ...] 

668 ] = tuple(self.crl_issuer) 

669 else: 

670 crl_issuer = None 

671 

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

673 

674 @property 

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

676 return self._full_name 

677 

678 @property 

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

680 return self._relative_name 

681 

682 @property 

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

684 return self._reasons 

685 

686 @property 

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

688 return self._crl_issuer 

689 

690 

691class ReasonFlags(utils.Enum): 

692 unspecified = "unspecified" 

693 key_compromise = "keyCompromise" 

694 ca_compromise = "cACompromise" 

695 affiliation_changed = "affiliationChanged" 

696 superseded = "superseded" 

697 cessation_of_operation = "cessationOfOperation" 

698 certificate_hold = "certificateHold" 

699 privilege_withdrawn = "privilegeWithdrawn" 

700 aa_compromise = "aACompromise" 

701 remove_from_crl = "removeFromCRL" 

702 

703 

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

705# CRLReason reason flags bit string mappings. 

706# ReasonFlags ::= BIT STRING { 

707# unused (0), 

708# keyCompromise (1), 

709# cACompromise (2), 

710# affiliationChanged (3), 

711# superseded (4), 

712# cessationOfOperation (5), 

713# certificateHold (6), 

714# privilegeWithdrawn (7), 

715# aACompromise (8) } 

716_REASON_BIT_MAPPING = { 

717 1: ReasonFlags.key_compromise, 

718 2: ReasonFlags.ca_compromise, 

719 3: ReasonFlags.affiliation_changed, 

720 4: ReasonFlags.superseded, 

721 5: ReasonFlags.cessation_of_operation, 

722 6: ReasonFlags.certificate_hold, 

723 7: ReasonFlags.privilege_withdrawn, 

724 8: ReasonFlags.aa_compromise, 

725} 

726 

727_CRLREASONFLAGS = { 

728 ReasonFlags.key_compromise: 1, 

729 ReasonFlags.ca_compromise: 2, 

730 ReasonFlags.affiliation_changed: 3, 

731 ReasonFlags.superseded: 4, 

732 ReasonFlags.cessation_of_operation: 5, 

733 ReasonFlags.certificate_hold: 6, 

734 ReasonFlags.privilege_withdrawn: 7, 

735 ReasonFlags.aa_compromise: 8, 

736} 

737 

738 

739class PolicyConstraints(ExtensionType): 

740 oid = ExtensionOID.POLICY_CONSTRAINTS 

741 

742 def __init__( 

743 self, 

744 require_explicit_policy: typing.Optional[int], 

745 inhibit_policy_mapping: typing.Optional[int], 

746 ) -> None: 

747 if require_explicit_policy is not None and not isinstance( 

748 require_explicit_policy, int 

749 ): 

750 raise TypeError( 

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

752 "None" 

753 ) 

754 

755 if inhibit_policy_mapping is not None and not isinstance( 

756 inhibit_policy_mapping, int 

757 ): 

758 raise TypeError( 

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

760 ) 

761 

762 if inhibit_policy_mapping is None and require_explicit_policy is None: 

763 raise ValueError( 

764 "At least one of require_explicit_policy and " 

765 "inhibit_policy_mapping must not be None" 

766 ) 

767 

768 self._require_explicit_policy = require_explicit_policy 

769 self._inhibit_policy_mapping = inhibit_policy_mapping 

770 

771 def __repr__(self) -> str: 

772 return ( 

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

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

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

776 ) 

777 

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

779 if not isinstance(other, PolicyConstraints): 

780 return NotImplemented 

781 

782 return ( 

783 self.require_explicit_policy == other.require_explicit_policy 

784 and self.inhibit_policy_mapping == other.inhibit_policy_mapping 

785 ) 

786 

787 def __hash__(self) -> int: 

788 return hash( 

789 (self.require_explicit_policy, self.inhibit_policy_mapping) 

790 ) 

791 

792 @property 

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

794 return self._require_explicit_policy 

795 

796 @property 

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

798 return self._inhibit_policy_mapping 

799 

800 def public_bytes(self) -> bytes: 

801 return rust_x509.encode_extension_value(self) 

802 

803 

804class CertificatePolicies(ExtensionType): 

805 oid = ExtensionOID.CERTIFICATE_POLICIES 

806 

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

808 policies = list(policies) 

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

810 raise TypeError( 

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

812 "PolicyInformation" 

813 ) 

814 

815 self._policies = policies 

816 

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

818 

819 def __repr__(self) -> str: 

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

821 

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

823 if not isinstance(other, CertificatePolicies): 

824 return NotImplemented 

825 

826 return self._policies == other._policies 

827 

828 def __hash__(self) -> int: 

829 return hash(tuple(self._policies)) 

830 

831 def public_bytes(self) -> bytes: 

832 return rust_x509.encode_extension_value(self) 

833 

834 

835class PolicyInformation: 

836 def __init__( 

837 self, 

838 policy_identifier: ObjectIdentifier, 

839 policy_qualifiers: typing.Optional[ 

840 typing.Iterable[typing.Union[str, UserNotice]] 

841 ], 

842 ) -> None: 

843 if not isinstance(policy_identifier, ObjectIdentifier): 

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

845 

846 self._policy_identifier = policy_identifier 

847 

848 if policy_qualifiers is not None: 

849 policy_qualifiers = list(policy_qualifiers) 

850 if not all( 

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

852 ): 

853 raise TypeError( 

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

855 "UserNotice objects or None" 

856 ) 

857 

858 self._policy_qualifiers = policy_qualifiers 

859 

860 def __repr__(self) -> str: 

861 return ( 

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

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

864 ) 

865 

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

867 if not isinstance(other, PolicyInformation): 

868 return NotImplemented 

869 

870 return ( 

871 self.policy_identifier == other.policy_identifier 

872 and self.policy_qualifiers == other.policy_qualifiers 

873 ) 

874 

875 def __hash__(self) -> int: 

876 if self.policy_qualifiers is not None: 

877 pq: typing.Optional[ 

878 typing.Tuple[typing.Union[str, UserNotice], ...] 

879 ] = tuple(self.policy_qualifiers) 

880 else: 

881 pq = None 

882 

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

884 

885 @property 

886 def policy_identifier(self) -> ObjectIdentifier: 

887 return self._policy_identifier 

888 

889 @property 

890 def policy_qualifiers( 

891 self, 

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

893 return self._policy_qualifiers 

894 

895 

896class UserNotice: 

897 def __init__( 

898 self, 

899 notice_reference: typing.Optional[NoticeReference], 

900 explicit_text: typing.Optional[str], 

901 ) -> None: 

902 if notice_reference and not isinstance( 

903 notice_reference, NoticeReference 

904 ): 

905 raise TypeError( 

906 "notice_reference must be None or a NoticeReference" 

907 ) 

908 

909 self._notice_reference = notice_reference 

910 self._explicit_text = explicit_text 

911 

912 def __repr__(self) -> str: 

913 return ( 

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

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

916 ) 

917 

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

919 if not isinstance(other, UserNotice): 

920 return NotImplemented 

921 

922 return ( 

923 self.notice_reference == other.notice_reference 

924 and self.explicit_text == other.explicit_text 

925 ) 

926 

927 def __hash__(self) -> int: 

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

929 

930 @property 

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

932 return self._notice_reference 

933 

934 @property 

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

936 return self._explicit_text 

937 

938 

939class NoticeReference: 

940 def __init__( 

941 self, 

942 organization: typing.Optional[str], 

943 notice_numbers: typing.Iterable[int], 

944 ) -> None: 

945 self._organization = organization 

946 notice_numbers = list(notice_numbers) 

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

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

949 

950 self._notice_numbers = notice_numbers 

951 

952 def __repr__(self) -> str: 

953 return ( 

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

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

956 ) 

957 

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

959 if not isinstance(other, NoticeReference): 

960 return NotImplemented 

961 

962 return ( 

963 self.organization == other.organization 

964 and self.notice_numbers == other.notice_numbers 

965 ) 

966 

967 def __hash__(self) -> int: 

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

969 

970 @property 

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

972 return self._organization 

973 

974 @property 

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

976 return self._notice_numbers 

977 

978 

979class ExtendedKeyUsage(ExtensionType): 

980 oid = ExtensionOID.EXTENDED_KEY_USAGE 

981 

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

983 usages = list(usages) 

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

985 raise TypeError( 

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

987 ) 

988 

989 self._usages = usages 

990 

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

992 

993 def __repr__(self) -> str: 

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

995 

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

997 if not isinstance(other, ExtendedKeyUsage): 

998 return NotImplemented 

999 

1000 return self._usages == other._usages 

1001 

1002 def __hash__(self) -> int: 

1003 return hash(tuple(self._usages)) 

1004 

1005 def public_bytes(self) -> bytes: 

1006 return rust_x509.encode_extension_value(self) 

1007 

1008 

1009class OCSPNoCheck(ExtensionType): 

1010 oid = ExtensionOID.OCSP_NO_CHECK 

1011 

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

1013 if not isinstance(other, OCSPNoCheck): 

1014 return NotImplemented 

1015 

1016 return True 

1017 

1018 def __hash__(self) -> int: 

1019 return hash(OCSPNoCheck) 

1020 

1021 def __repr__(self) -> str: 

1022 return "<OCSPNoCheck()>" 

1023 

1024 def public_bytes(self) -> bytes: 

1025 return rust_x509.encode_extension_value(self) 

1026 

1027 

1028class PrecertPoison(ExtensionType): 

1029 oid = ExtensionOID.PRECERT_POISON 

1030 

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

1032 if not isinstance(other, PrecertPoison): 

1033 return NotImplemented 

1034 

1035 return True 

1036 

1037 def __hash__(self) -> int: 

1038 return hash(PrecertPoison) 

1039 

1040 def __repr__(self) -> str: 

1041 return "<PrecertPoison()>" 

1042 

1043 def public_bytes(self) -> bytes: 

1044 return rust_x509.encode_extension_value(self) 

1045 

1046 

1047class TLSFeature(ExtensionType): 

1048 oid = ExtensionOID.TLS_FEATURE 

1049 

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

1051 features = list(features) 

1052 if ( 

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

1054 or len(features) == 0 

1055 ): 

1056 raise TypeError( 

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

1058 "enum" 

1059 ) 

1060 

1061 self._features = features 

1062 

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

1064 

1065 def __repr__(self) -> str: 

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

1067 

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

1069 if not isinstance(other, TLSFeature): 

1070 return NotImplemented 

1071 

1072 return self._features == other._features 

1073 

1074 def __hash__(self) -> int: 

1075 return hash(tuple(self._features)) 

1076 

1077 def public_bytes(self) -> bytes: 

1078 return rust_x509.encode_extension_value(self) 

1079 

1080 

1081class TLSFeatureType(utils.Enum): 

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

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

1084 # X.509 certificate. 

1085 status_request = 5 

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

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

1088 # servers. 

1089 status_request_v2 = 17 

1090 

1091 

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

1093 

1094 

1095class InhibitAnyPolicy(ExtensionType): 

1096 oid = ExtensionOID.INHIBIT_ANY_POLICY 

1097 

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

1099 if not isinstance(skip_certs, int): 

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

1101 

1102 if skip_certs < 0: 

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

1104 

1105 self._skip_certs = skip_certs 

1106 

1107 def __repr__(self) -> str: 

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

1109 

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

1111 if not isinstance(other, InhibitAnyPolicy): 

1112 return NotImplemented 

1113 

1114 return self.skip_certs == other.skip_certs 

1115 

1116 def __hash__(self) -> int: 

1117 return hash(self.skip_certs) 

1118 

1119 @property 

1120 def skip_certs(self) -> int: 

1121 return self._skip_certs 

1122 

1123 def public_bytes(self) -> bytes: 

1124 return rust_x509.encode_extension_value(self) 

1125 

1126 

1127class KeyUsage(ExtensionType): 

1128 oid = ExtensionOID.KEY_USAGE 

1129 

1130 def __init__( 

1131 self, 

1132 digital_signature: bool, 

1133 content_commitment: bool, 

1134 key_encipherment: bool, 

1135 data_encipherment: bool, 

1136 key_agreement: bool, 

1137 key_cert_sign: bool, 

1138 crl_sign: bool, 

1139 encipher_only: bool, 

1140 decipher_only: bool, 

1141 ) -> None: 

1142 if not key_agreement and (encipher_only or decipher_only): 

1143 raise ValueError( 

1144 "encipher_only and decipher_only can only be true when " 

1145 "key_agreement is true" 

1146 ) 

1147 

1148 self._digital_signature = digital_signature 

1149 self._content_commitment = content_commitment 

1150 self._key_encipherment = key_encipherment 

1151 self._data_encipherment = data_encipherment 

1152 self._key_agreement = key_agreement 

1153 self._key_cert_sign = key_cert_sign 

1154 self._crl_sign = crl_sign 

1155 self._encipher_only = encipher_only 

1156 self._decipher_only = decipher_only 

1157 

1158 @property 

1159 def digital_signature(self) -> bool: 

1160 return self._digital_signature 

1161 

1162 @property 

1163 def content_commitment(self) -> bool: 

1164 return self._content_commitment 

1165 

1166 @property 

1167 def key_encipherment(self) -> bool: 

1168 return self._key_encipherment 

1169 

1170 @property 

1171 def data_encipherment(self) -> bool: 

1172 return self._data_encipherment 

1173 

1174 @property 

1175 def key_agreement(self) -> bool: 

1176 return self._key_agreement 

1177 

1178 @property 

1179 def key_cert_sign(self) -> bool: 

1180 return self._key_cert_sign 

1181 

1182 @property 

1183 def crl_sign(self) -> bool: 

1184 return self._crl_sign 

1185 

1186 @property 

1187 def encipher_only(self) -> bool: 

1188 if not self.key_agreement: 

1189 raise ValueError( 

1190 "encipher_only is undefined unless key_agreement is true" 

1191 ) 

1192 else: 

1193 return self._encipher_only 

1194 

1195 @property 

1196 def decipher_only(self) -> bool: 

1197 if not self.key_agreement: 

1198 raise ValueError( 

1199 "decipher_only is undefined unless key_agreement is true" 

1200 ) 

1201 else: 

1202 return self._decipher_only 

1203 

1204 def __repr__(self) -> str: 

1205 try: 

1206 encipher_only = self.encipher_only 

1207 decipher_only = self.decipher_only 

1208 except ValueError: 

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

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

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

1212 encipher_only = False 

1213 decipher_only = False 

1214 

1215 return ( 

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

1217 "content_commitment={0.content_commitment}, " 

1218 "key_encipherment={0.key_encipherment}, " 

1219 "data_encipherment={0.data_encipherment}, " 

1220 "key_agreement={0.key_agreement}, " 

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

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

1223 ).format(self, encipher_only, decipher_only) 

1224 

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

1226 if not isinstance(other, KeyUsage): 

1227 return NotImplemented 

1228 

1229 return ( 

1230 self.digital_signature == other.digital_signature 

1231 and self.content_commitment == other.content_commitment 

1232 and self.key_encipherment == other.key_encipherment 

1233 and self.data_encipherment == other.data_encipherment 

1234 and self.key_agreement == other.key_agreement 

1235 and self.key_cert_sign == other.key_cert_sign 

1236 and self.crl_sign == other.crl_sign 

1237 and self._encipher_only == other._encipher_only 

1238 and self._decipher_only == other._decipher_only 

1239 ) 

1240 

1241 def __hash__(self) -> int: 

1242 return hash( 

1243 ( 

1244 self.digital_signature, 

1245 self.content_commitment, 

1246 self.key_encipherment, 

1247 self.data_encipherment, 

1248 self.key_agreement, 

1249 self.key_cert_sign, 

1250 self.crl_sign, 

1251 self._encipher_only, 

1252 self._decipher_only, 

1253 ) 

1254 ) 

1255 

1256 def public_bytes(self) -> bytes: 

1257 return rust_x509.encode_extension_value(self) 

1258 

1259 

1260class NameConstraints(ExtensionType): 

1261 oid = ExtensionOID.NAME_CONSTRAINTS 

1262 

1263 def __init__( 

1264 self, 

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

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

1267 ) -> None: 

1268 if permitted_subtrees is not None: 

1269 permitted_subtrees = list(permitted_subtrees) 

1270 if not permitted_subtrees: 

1271 raise ValueError( 

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

1273 ) 

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

1275 raise TypeError( 

1276 "permitted_subtrees must be a list of GeneralName objects " 

1277 "or None" 

1278 ) 

1279 

1280 self._validate_tree(permitted_subtrees) 

1281 

1282 if excluded_subtrees is not None: 

1283 excluded_subtrees = list(excluded_subtrees) 

1284 if not excluded_subtrees: 

1285 raise ValueError( 

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

1287 ) 

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

1289 raise TypeError( 

1290 "excluded_subtrees must be a list of GeneralName objects " 

1291 "or None" 

1292 ) 

1293 

1294 self._validate_tree(excluded_subtrees) 

1295 

1296 if permitted_subtrees is None and excluded_subtrees is None: 

1297 raise ValueError( 

1298 "At least one of permitted_subtrees and excluded_subtrees " 

1299 "must not be None" 

1300 ) 

1301 

1302 self._permitted_subtrees = permitted_subtrees 

1303 self._excluded_subtrees = excluded_subtrees 

1304 

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

1306 if not isinstance(other, NameConstraints): 

1307 return NotImplemented 

1308 

1309 return ( 

1310 self.excluded_subtrees == other.excluded_subtrees 

1311 and self.permitted_subtrees == other.permitted_subtrees 

1312 ) 

1313 

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

1315 self._validate_ip_name(tree) 

1316 self._validate_dns_name(tree) 

1317 

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

1319 if any( 

1320 isinstance(name, IPAddress) 

1321 and not isinstance( 

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

1323 ) 

1324 for name in tree 

1325 ): 

1326 raise TypeError( 

1327 "IPAddress name constraints must be an IPv4Network or" 

1328 " IPv6Network object" 

1329 ) 

1330 

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

1332 if any( 

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

1334 ): 

1335 raise ValueError( 

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

1337 " character" 

1338 ) 

1339 

1340 def __repr__(self) -> str: 

1341 return ( 

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

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

1344 ) 

1345 

1346 def __hash__(self) -> int: 

1347 if self.permitted_subtrees is not None: 

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

1349 self.permitted_subtrees 

1350 ) 

1351 else: 

1352 ps = None 

1353 

1354 if self.excluded_subtrees is not None: 

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

1356 self.excluded_subtrees 

1357 ) 

1358 else: 

1359 es = None 

1360 

1361 return hash((ps, es)) 

1362 

1363 @property 

1364 def permitted_subtrees( 

1365 self, 

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

1367 return self._permitted_subtrees 

1368 

1369 @property 

1370 def excluded_subtrees( 

1371 self, 

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

1373 return self._excluded_subtrees 

1374 

1375 def public_bytes(self) -> bytes: 

1376 return rust_x509.encode_extension_value(self) 

1377 

1378 

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

1380 def __init__( 

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

1382 ) -> None: 

1383 if not isinstance(oid, ObjectIdentifier): 

1384 raise TypeError( 

1385 "oid argument must be an ObjectIdentifier instance." 

1386 ) 

1387 

1388 if not isinstance(critical, bool): 

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

1390 

1391 self._oid = oid 

1392 self._critical = critical 

1393 self._value = value 

1394 

1395 @property 

1396 def oid(self) -> ObjectIdentifier: 

1397 return self._oid 

1398 

1399 @property 

1400 def critical(self) -> bool: 

1401 return self._critical 

1402 

1403 @property 

1404 def value(self) -> ExtensionTypeVar: 

1405 return self._value 

1406 

1407 def __repr__(self) -> str: 

1408 return ( 

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

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

1411 ).format(self) 

1412 

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

1414 if not isinstance(other, Extension): 

1415 return NotImplemented 

1416 

1417 return ( 

1418 self.oid == other.oid 

1419 and self.critical == other.critical 

1420 and self.value == other.value 

1421 ) 

1422 

1423 def __hash__(self) -> int: 

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

1425 

1426 

1427class GeneralNames: 

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

1429 general_names = list(general_names) 

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

1431 raise TypeError( 

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

1433 "object conforming to the GeneralName interface" 

1434 ) 

1435 

1436 self._general_names = general_names 

1437 

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

1439 

1440 @typing.overload 

1441 def get_values_for_type( 

1442 self, 

1443 type: typing.Union[ 

1444 typing.Type[DNSName], 

1445 typing.Type[UniformResourceIdentifier], 

1446 typing.Type[RFC822Name], 

1447 ], 

1448 ) -> typing.List[str]: 

1449 ... 

1450 

1451 @typing.overload 

1452 def get_values_for_type( 

1453 self, 

1454 type: typing.Type[DirectoryName], 

1455 ) -> typing.List[Name]: 

1456 ... 

1457 

1458 @typing.overload 

1459 def get_values_for_type( 

1460 self, 

1461 type: typing.Type[RegisteredID], 

1462 ) -> typing.List[ObjectIdentifier]: 

1463 ... 

1464 

1465 @typing.overload 

1466 def get_values_for_type( 

1467 self, type: typing.Type[IPAddress] 

1468 ) -> typing.List[_IPAddressTypes]: 

1469 ... 

1470 

1471 @typing.overload 

1472 def get_values_for_type( 

1473 self, type: typing.Type[OtherName] 

1474 ) -> typing.List[OtherName]: 

1475 ... 

1476 

1477 def get_values_for_type( 

1478 self, 

1479 type: typing.Union[ 

1480 typing.Type[DNSName], 

1481 typing.Type[DirectoryName], 

1482 typing.Type[IPAddress], 

1483 typing.Type[OtherName], 

1484 typing.Type[RFC822Name], 

1485 typing.Type[RegisteredID], 

1486 typing.Type[UniformResourceIdentifier], 

1487 ], 

1488 ) -> typing.Union[ 

1489 typing.List[_IPAddressTypes], 

1490 typing.List[str], 

1491 typing.List[OtherName], 

1492 typing.List[Name], 

1493 typing.List[ObjectIdentifier], 

1494 ]: 

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

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

1497 # just one value. 

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

1499 if type != OtherName: 

1500 return [i.value for i in objs] 

1501 return list(objs) 

1502 

1503 def __repr__(self) -> str: 

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

1505 

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

1507 if not isinstance(other, GeneralNames): 

1508 return NotImplemented 

1509 

1510 return self._general_names == other._general_names 

1511 

1512 def __hash__(self) -> int: 

1513 return hash(tuple(self._general_names)) 

1514 

1515 

1516class SubjectAlternativeName(ExtensionType): 

1517 oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME 

1518 

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

1520 self._general_names = GeneralNames(general_names) 

1521 

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

1523 

1524 @typing.overload 

1525 def get_values_for_type( 

1526 self, 

1527 type: typing.Union[ 

1528 typing.Type[DNSName], 

1529 typing.Type[UniformResourceIdentifier], 

1530 typing.Type[RFC822Name], 

1531 ], 

1532 ) -> typing.List[str]: 

1533 ... 

1534 

1535 @typing.overload 

1536 def get_values_for_type( 

1537 self, 

1538 type: typing.Type[DirectoryName], 

1539 ) -> typing.List[Name]: 

1540 ... 

1541 

1542 @typing.overload 

1543 def get_values_for_type( 

1544 self, 

1545 type: typing.Type[RegisteredID], 

1546 ) -> typing.List[ObjectIdentifier]: 

1547 ... 

1548 

1549 @typing.overload 

1550 def get_values_for_type( 

1551 self, type: typing.Type[IPAddress] 

1552 ) -> typing.List[_IPAddressTypes]: 

1553 ... 

1554 

1555 @typing.overload 

1556 def get_values_for_type( 

1557 self, type: typing.Type[OtherName] 

1558 ) -> typing.List[OtherName]: 

1559 ... 

1560 

1561 def get_values_for_type( 

1562 self, 

1563 type: typing.Union[ 

1564 typing.Type[DNSName], 

1565 typing.Type[DirectoryName], 

1566 typing.Type[IPAddress], 

1567 typing.Type[OtherName], 

1568 typing.Type[RFC822Name], 

1569 typing.Type[RegisteredID], 

1570 typing.Type[UniformResourceIdentifier], 

1571 ], 

1572 ) -> typing.Union[ 

1573 typing.List[_IPAddressTypes], 

1574 typing.List[str], 

1575 typing.List[OtherName], 

1576 typing.List[Name], 

1577 typing.List[ObjectIdentifier], 

1578 ]: 

1579 return self._general_names.get_values_for_type(type) 

1580 

1581 def __repr__(self) -> str: 

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

1583 

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

1585 if not isinstance(other, SubjectAlternativeName): 

1586 return NotImplemented 

1587 

1588 return self._general_names == other._general_names 

1589 

1590 def __hash__(self) -> int: 

1591 return hash(self._general_names) 

1592 

1593 def public_bytes(self) -> bytes: 

1594 return rust_x509.encode_extension_value(self) 

1595 

1596 

1597class IssuerAlternativeName(ExtensionType): 

1598 oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME 

1599 

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

1601 self._general_names = GeneralNames(general_names) 

1602 

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

1604 

1605 @typing.overload 

1606 def get_values_for_type( 

1607 self, 

1608 type: typing.Union[ 

1609 typing.Type[DNSName], 

1610 typing.Type[UniformResourceIdentifier], 

1611 typing.Type[RFC822Name], 

1612 ], 

1613 ) -> typing.List[str]: 

1614 ... 

1615 

1616 @typing.overload 

1617 def get_values_for_type( 

1618 self, 

1619 type: typing.Type[DirectoryName], 

1620 ) -> typing.List[Name]: 

1621 ... 

1622 

1623 @typing.overload 

1624 def get_values_for_type( 

1625 self, 

1626 type: typing.Type[RegisteredID], 

1627 ) -> typing.List[ObjectIdentifier]: 

1628 ... 

1629 

1630 @typing.overload 

1631 def get_values_for_type( 

1632 self, type: typing.Type[IPAddress] 

1633 ) -> typing.List[_IPAddressTypes]: 

1634 ... 

1635 

1636 @typing.overload 

1637 def get_values_for_type( 

1638 self, type: typing.Type[OtherName] 

1639 ) -> typing.List[OtherName]: 

1640 ... 

1641 

1642 def get_values_for_type( 

1643 self, 

1644 type: typing.Union[ 

1645 typing.Type[DNSName], 

1646 typing.Type[DirectoryName], 

1647 typing.Type[IPAddress], 

1648 typing.Type[OtherName], 

1649 typing.Type[RFC822Name], 

1650 typing.Type[RegisteredID], 

1651 typing.Type[UniformResourceIdentifier], 

1652 ], 

1653 ) -> typing.Union[ 

1654 typing.List[_IPAddressTypes], 

1655 typing.List[str], 

1656 typing.List[OtherName], 

1657 typing.List[Name], 

1658 typing.List[ObjectIdentifier], 

1659 ]: 

1660 return self._general_names.get_values_for_type(type) 

1661 

1662 def __repr__(self) -> str: 

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

1664 

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

1666 if not isinstance(other, IssuerAlternativeName): 

1667 return NotImplemented 

1668 

1669 return self._general_names == other._general_names 

1670 

1671 def __hash__(self) -> int: 

1672 return hash(self._general_names) 

1673 

1674 def public_bytes(self) -> bytes: 

1675 return rust_x509.encode_extension_value(self) 

1676 

1677 

1678class CertificateIssuer(ExtensionType): 

1679 oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER 

1680 

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

1682 self._general_names = GeneralNames(general_names) 

1683 

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

1685 

1686 @typing.overload 

1687 def get_values_for_type( 

1688 self, 

1689 type: typing.Union[ 

1690 typing.Type[DNSName], 

1691 typing.Type[UniformResourceIdentifier], 

1692 typing.Type[RFC822Name], 

1693 ], 

1694 ) -> typing.List[str]: 

1695 ... 

1696 

1697 @typing.overload 

1698 def get_values_for_type( 

1699 self, 

1700 type: typing.Type[DirectoryName], 

1701 ) -> typing.List[Name]: 

1702 ... 

1703 

1704 @typing.overload 

1705 def get_values_for_type( 

1706 self, 

1707 type: typing.Type[RegisteredID], 

1708 ) -> typing.List[ObjectIdentifier]: 

1709 ... 

1710 

1711 @typing.overload 

1712 def get_values_for_type( 

1713 self, type: typing.Type[IPAddress] 

1714 ) -> typing.List[_IPAddressTypes]: 

1715 ... 

1716 

1717 @typing.overload 

1718 def get_values_for_type( 

1719 self, type: typing.Type[OtherName] 

1720 ) -> typing.List[OtherName]: 

1721 ... 

1722 

1723 def get_values_for_type( 

1724 self, 

1725 type: typing.Union[ 

1726 typing.Type[DNSName], 

1727 typing.Type[DirectoryName], 

1728 typing.Type[IPAddress], 

1729 typing.Type[OtherName], 

1730 typing.Type[RFC822Name], 

1731 typing.Type[RegisteredID], 

1732 typing.Type[UniformResourceIdentifier], 

1733 ], 

1734 ) -> typing.Union[ 

1735 typing.List[_IPAddressTypes], 

1736 typing.List[str], 

1737 typing.List[OtherName], 

1738 typing.List[Name], 

1739 typing.List[ObjectIdentifier], 

1740 ]: 

1741 return self._general_names.get_values_for_type(type) 

1742 

1743 def __repr__(self) -> str: 

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

1745 

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

1747 if not isinstance(other, CertificateIssuer): 

1748 return NotImplemented 

1749 

1750 return self._general_names == other._general_names 

1751 

1752 def __hash__(self) -> int: 

1753 return hash(self._general_names) 

1754 

1755 def public_bytes(self) -> bytes: 

1756 return rust_x509.encode_extension_value(self) 

1757 

1758 

1759class CRLReason(ExtensionType): 

1760 oid = CRLEntryExtensionOID.CRL_REASON 

1761 

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

1763 if not isinstance(reason, ReasonFlags): 

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

1765 

1766 self._reason = reason 

1767 

1768 def __repr__(self) -> str: 

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

1770 

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

1772 if not isinstance(other, CRLReason): 

1773 return NotImplemented 

1774 

1775 return self.reason == other.reason 

1776 

1777 def __hash__(self) -> int: 

1778 return hash(self.reason) 

1779 

1780 @property 

1781 def reason(self) -> ReasonFlags: 

1782 return self._reason 

1783 

1784 def public_bytes(self) -> bytes: 

1785 return rust_x509.encode_extension_value(self) 

1786 

1787 

1788class InvalidityDate(ExtensionType): 

1789 oid = CRLEntryExtensionOID.INVALIDITY_DATE 

1790 

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

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

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

1794 

1795 self._invalidity_date = invalidity_date 

1796 

1797 def __repr__(self) -> str: 

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

1799 self._invalidity_date 

1800 ) 

1801 

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

1803 if not isinstance(other, InvalidityDate): 

1804 return NotImplemented 

1805 

1806 return self.invalidity_date == other.invalidity_date 

1807 

1808 def __hash__(self) -> int: 

1809 return hash(self.invalidity_date) 

1810 

1811 @property 

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

1813 return self._invalidity_date 

1814 

1815 def public_bytes(self) -> bytes: 

1816 return rust_x509.encode_extension_value(self) 

1817 

1818 

1819class PrecertificateSignedCertificateTimestamps(ExtensionType): 

1820 oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS 

1821 

1822 def __init__( 

1823 self, 

1824 signed_certificate_timestamps: typing.Iterable[ 

1825 SignedCertificateTimestamp 

1826 ], 

1827 ) -> None: 

1828 signed_certificate_timestamps = list(signed_certificate_timestamps) 

1829 if not all( 

1830 isinstance(sct, SignedCertificateTimestamp) 

1831 for sct in signed_certificate_timestamps 

1832 ): 

1833 raise TypeError( 

1834 "Every item in the signed_certificate_timestamps list must be " 

1835 "a SignedCertificateTimestamp" 

1836 ) 

1837 self._signed_certificate_timestamps = signed_certificate_timestamps 

1838 

1839 __len__, __iter__, __getitem__ = _make_sequence_methods( 

1840 "_signed_certificate_timestamps" 

1841 ) 

1842 

1843 def __repr__(self) -> str: 

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

1845 list(self) 

1846 ) 

1847 

1848 def __hash__(self) -> int: 

1849 return hash(tuple(self._signed_certificate_timestamps)) 

1850 

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

1852 if not isinstance(other, PrecertificateSignedCertificateTimestamps): 

1853 return NotImplemented 

1854 

1855 return ( 

1856 self._signed_certificate_timestamps 

1857 == other._signed_certificate_timestamps 

1858 ) 

1859 

1860 def public_bytes(self) -> bytes: 

1861 return rust_x509.encode_extension_value(self) 

1862 

1863 

1864class SignedCertificateTimestamps(ExtensionType): 

1865 oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS 

1866 

1867 def __init__( 

1868 self, 

1869 signed_certificate_timestamps: typing.Iterable[ 

1870 SignedCertificateTimestamp 

1871 ], 

1872 ) -> None: 

1873 signed_certificate_timestamps = list(signed_certificate_timestamps) 

1874 if not all( 

1875 isinstance(sct, SignedCertificateTimestamp) 

1876 for sct in signed_certificate_timestamps 

1877 ): 

1878 raise TypeError( 

1879 "Every item in the signed_certificate_timestamps list must be " 

1880 "a SignedCertificateTimestamp" 

1881 ) 

1882 self._signed_certificate_timestamps = signed_certificate_timestamps 

1883 

1884 __len__, __iter__, __getitem__ = _make_sequence_methods( 

1885 "_signed_certificate_timestamps" 

1886 ) 

1887 

1888 def __repr__(self) -> str: 

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

1890 

1891 def __hash__(self) -> int: 

1892 return hash(tuple(self._signed_certificate_timestamps)) 

1893 

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

1895 if not isinstance(other, SignedCertificateTimestamps): 

1896 return NotImplemented 

1897 

1898 return ( 

1899 self._signed_certificate_timestamps 

1900 == other._signed_certificate_timestamps 

1901 ) 

1902 

1903 def public_bytes(self) -> bytes: 

1904 return rust_x509.encode_extension_value(self) 

1905 

1906 

1907class OCSPNonce(ExtensionType): 

1908 oid = OCSPExtensionOID.NONCE 

1909 

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

1911 if not isinstance(nonce, bytes): 

1912 raise TypeError("nonce must be bytes") 

1913 

1914 self._nonce = nonce 

1915 

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

1917 if not isinstance(other, OCSPNonce): 

1918 return NotImplemented 

1919 

1920 return self.nonce == other.nonce 

1921 

1922 def __hash__(self) -> int: 

1923 return hash(self.nonce) 

1924 

1925 def __repr__(self) -> str: 

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

1927 

1928 @property 

1929 def nonce(self) -> bytes: 

1930 return self._nonce 

1931 

1932 def public_bytes(self) -> bytes: 

1933 return rust_x509.encode_extension_value(self) 

1934 

1935 

1936class OCSPAcceptableResponses(ExtensionType): 

1937 oid = OCSPExtensionOID.ACCEPTABLE_RESPONSES 

1938 

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

1940 responses = list(responses) 

1941 if any(not isinstance(r, ObjectIdentifier) for r in responses): 

1942 raise TypeError("All responses must be ObjectIdentifiers") 

1943 

1944 self._responses = responses 

1945 

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

1947 if not isinstance(other, OCSPAcceptableResponses): 

1948 return NotImplemented 

1949 

1950 return self._responses == other._responses 

1951 

1952 def __hash__(self) -> int: 

1953 return hash(tuple(self._responses)) 

1954 

1955 def __repr__(self) -> str: 

1956 return f"<OCSPAcceptableResponses(responses={self._responses})>" 

1957 

1958 def __iter__(self) -> typing.Iterator[ObjectIdentifier]: 

1959 return iter(self._responses) 

1960 

1961 def public_bytes(self) -> bytes: 

1962 return rust_x509.encode_extension_value(self) 

1963 

1964 

1965class IssuingDistributionPoint(ExtensionType): 

1966 oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT 

1967 

1968 def __init__( 

1969 self, 

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

1971 relative_name: typing.Optional[RelativeDistinguishedName], 

1972 only_contains_user_certs: bool, 

1973 only_contains_ca_certs: bool, 

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

1975 indirect_crl: bool, 

1976 only_contains_attribute_certs: bool, 

1977 ) -> None: 

1978 if full_name is not None: 

1979 full_name = list(full_name) 

1980 

1981 if only_some_reasons and ( 

1982 not isinstance(only_some_reasons, frozenset) 

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

1984 ): 

1985 raise TypeError( 

1986 "only_some_reasons must be None or frozenset of ReasonFlags" 

1987 ) 

1988 

1989 if only_some_reasons and ( 

1990 ReasonFlags.unspecified in only_some_reasons 

1991 or ReasonFlags.remove_from_crl in only_some_reasons 

1992 ): 

1993 raise ValueError( 

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

1995 "IssuingDistributionPoint" 

1996 ) 

1997 

1998 if not ( 

1999 isinstance(only_contains_user_certs, bool) 

2000 and isinstance(only_contains_ca_certs, bool) 

2001 and isinstance(indirect_crl, bool) 

2002 and isinstance(only_contains_attribute_certs, bool) 

2003 ): 

2004 raise TypeError( 

2005 "only_contains_user_certs, only_contains_ca_certs, " 

2006 "indirect_crl and only_contains_attribute_certs " 

2007 "must all be boolean." 

2008 ) 

2009 

2010 crl_constraints = [ 

2011 only_contains_user_certs, 

2012 only_contains_ca_certs, 

2013 indirect_crl, 

2014 only_contains_attribute_certs, 

2015 ] 

2016 

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

2018 raise ValueError( 

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

2020 "only_contains_user_certs, only_contains_ca_certs, " 

2021 "indirect_crl, only_contains_attribute_certs" 

2022 ) 

2023 

2024 if not any( 

2025 [ 

2026 only_contains_user_certs, 

2027 only_contains_ca_certs, 

2028 indirect_crl, 

2029 only_contains_attribute_certs, 

2030 full_name, 

2031 relative_name, 

2032 only_some_reasons, 

2033 ] 

2034 ): 

2035 raise ValueError( 

2036 "Cannot create empty extension: " 

2037 "if only_contains_user_certs, only_contains_ca_certs, " 

2038 "indirect_crl, and only_contains_attribute_certs are all False" 

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

2040 "must have a value." 

2041 ) 

2042 

2043 self._only_contains_user_certs = only_contains_user_certs 

2044 self._only_contains_ca_certs = only_contains_ca_certs 

2045 self._indirect_crl = indirect_crl 

2046 self._only_contains_attribute_certs = only_contains_attribute_certs 

2047 self._only_some_reasons = only_some_reasons 

2048 self._full_name = full_name 

2049 self._relative_name = relative_name 

2050 

2051 def __repr__(self) -> str: 

2052 return ( 

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

2054 "relative_name={0.relative_name}, " 

2055 "only_contains_user_certs={0.only_contains_user_certs}, " 

2056 "only_contains_ca_certs={0.only_contains_ca_certs}, " 

2057 "only_some_reasons={0.only_some_reasons}, " 

2058 "indirect_crl={0.indirect_crl}, " 

2059 "only_contains_attribute_certs=" 

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

2061 ) 

2062 

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

2064 if not isinstance(other, IssuingDistributionPoint): 

2065 return NotImplemented 

2066 

2067 return ( 

2068 self.full_name == other.full_name 

2069 and self.relative_name == other.relative_name 

2070 and self.only_contains_user_certs == other.only_contains_user_certs 

2071 and self.only_contains_ca_certs == other.only_contains_ca_certs 

2072 and self.only_some_reasons == other.only_some_reasons 

2073 and self.indirect_crl == other.indirect_crl 

2074 and self.only_contains_attribute_certs 

2075 == other.only_contains_attribute_certs 

2076 ) 

2077 

2078 def __hash__(self) -> int: 

2079 return hash( 

2080 ( 

2081 self.full_name, 

2082 self.relative_name, 

2083 self.only_contains_user_certs, 

2084 self.only_contains_ca_certs, 

2085 self.only_some_reasons, 

2086 self.indirect_crl, 

2087 self.only_contains_attribute_certs, 

2088 ) 

2089 ) 

2090 

2091 @property 

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

2093 return self._full_name 

2094 

2095 @property 

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

2097 return self._relative_name 

2098 

2099 @property 

2100 def only_contains_user_certs(self) -> bool: 

2101 return self._only_contains_user_certs 

2102 

2103 @property 

2104 def only_contains_ca_certs(self) -> bool: 

2105 return self._only_contains_ca_certs 

2106 

2107 @property 

2108 def only_some_reasons( 

2109 self, 

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

2111 return self._only_some_reasons 

2112 

2113 @property 

2114 def indirect_crl(self) -> bool: 

2115 return self._indirect_crl 

2116 

2117 @property 

2118 def only_contains_attribute_certs(self) -> bool: 

2119 return self._only_contains_attribute_certs 

2120 

2121 def public_bytes(self) -> bytes: 

2122 return rust_x509.encode_extension_value(self) 

2123 

2124 

2125class MSCertificateTemplate(ExtensionType): 

2126 oid = ExtensionOID.MS_CERTIFICATE_TEMPLATE 

2127 

2128 def __init__( 

2129 self, 

2130 template_id: ObjectIdentifier, 

2131 major_version: typing.Optional[int], 

2132 minor_version: typing.Optional[int], 

2133 ) -> None: 

2134 if not isinstance(template_id, ObjectIdentifier): 

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

2136 self._template_id = template_id 

2137 if ( 

2138 major_version is not None and not isinstance(major_version, int) 

2139 ) or ( 

2140 minor_version is not None and not isinstance(minor_version, int) 

2141 ): 

2142 raise TypeError( 

2143 "major_version and minor_version must be integers or None" 

2144 ) 

2145 self._major_version = major_version 

2146 self._minor_version = minor_version 

2147 

2148 @property 

2149 def template_id(self) -> ObjectIdentifier: 

2150 return self._template_id 

2151 

2152 @property 

2153 def major_version(self) -> typing.Optional[int]: 

2154 return self._major_version 

2155 

2156 @property 

2157 def minor_version(self) -> typing.Optional[int]: 

2158 return self._minor_version 

2159 

2160 def __repr__(self) -> str: 

2161 return ( 

2162 f"<MSCertificateTemplate(template_id={self.template_id}, " 

2163 f"major_version={self.major_version}, " 

2164 f"minor_version={self.minor_version})>" 

2165 ) 

2166 

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

2168 if not isinstance(other, MSCertificateTemplate): 

2169 return NotImplemented 

2170 

2171 return ( 

2172 self.template_id == other.template_id 

2173 and self.major_version == other.major_version 

2174 and self.minor_version == other.minor_version 

2175 ) 

2176 

2177 def __hash__(self) -> int: 

2178 return hash((self.template_id, self.major_version, self.minor_version)) 

2179 

2180 def public_bytes(self) -> bytes: 

2181 return rust_x509.encode_extension_value(self) 

2182 

2183 

2184class UnrecognizedExtension(ExtensionType): 

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

2186 if not isinstance(oid, ObjectIdentifier): 

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

2188 self._oid = oid 

2189 self._value = value 

2190 

2191 @property 

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

2193 return self._oid 

2194 

2195 @property 

2196 def value(self) -> bytes: 

2197 return self._value 

2198 

2199 def __repr__(self) -> str: 

2200 return ( 

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

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

2203 ) 

2204 

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

2206 if not isinstance(other, UnrecognizedExtension): 

2207 return NotImplemented 

2208 

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

2210 

2211 def __hash__(self) -> int: 

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

2213 

2214 def public_bytes(self) -> bytes: 

2215 return self.value