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

983 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +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 CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES, 

20 CERTIFICATE_PUBLIC_KEY_TYPES, 

21) 

22from cryptography.x509.certificate_transparency import ( 

23 SignedCertificateTimestamp, 

24) 

25from cryptography.x509.general_name import ( 

26 DNSName, 

27 DirectoryName, 

28 GeneralName, 

29 IPAddress, 

30 OtherName, 

31 RFC822Name, 

32 RegisteredID, 

33 UniformResourceIdentifier, 

34 _IPADDRESS_TYPES, 

35) 

36from cryptography.x509.name import Name, RelativeDistinguishedName 

37from cryptography.x509.oid import ( 

38 CRLEntryExtensionOID, 

39 ExtensionOID, 

40 OCSPExtensionOID, 

41 ObjectIdentifier, 

42) 

43 

44ExtensionTypeVar = typing.TypeVar( 

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

46) 

47 

48 

49def _key_identifier_from_public_key( 

50 public_key: CERTIFICATE_PUBLIC_KEY_TYPES, 

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(DuplicateExtension, self).__init__(msg) 

89 self.oid = oid 

90 

91 

92class ExtensionNotFound(Exception): 

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

94 super(ExtensionNotFound, self).__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 {0!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("No {} extension was found".format(oid), 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 "No {} extension was found".format(extclass), extclass.oid 

143 ) 

144 

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

146 

147 def __repr__(self) -> str: 

148 return "<Extensions({})>".format(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 "<CRLNumber({})>".format(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 CERTIFICATE_PUBLIC_KEY_TYPES 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: CERTIFICATE_ISSUER_PUBLIC_KEY_TYPES 

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: CERTIFICATE_PUBLIC_KEY_TYPES 

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 "<SubjectKeyIdentifier(digest={0!r})>".format(self.digest) 

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 "<AuthorityInformationAccess({})>".format(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 "<SubjectInformationAccess({})>".format(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 "<DeltaCRLIndicator(crl_number={0.crl_number})>".format(self) 

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 "<CRLDistributionPoints({})>".format(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 "<FreshestCRL({})>".format(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 

593 if full_name is not None: 

594 full_name = list(full_name) 

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

596 raise TypeError( 

597 "full_name must be a list of GeneralName objects" 

598 ) 

599 

600 if relative_name: 

601 if not isinstance(relative_name, RelativeDistinguishedName): 

602 raise TypeError( 

603 "relative_name must be a RelativeDistinguishedName" 

604 ) 

605 

606 if crl_issuer is not None: 

607 crl_issuer = list(crl_issuer) 

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

609 raise TypeError( 

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

611 ) 

612 

613 if reasons and ( 

614 not isinstance(reasons, frozenset) 

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

616 ): 

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

618 

619 if reasons and ( 

620 ReasonFlags.unspecified in reasons 

621 or ReasonFlags.remove_from_crl in reasons 

622 ): 

623 raise ValueError( 

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

625 "DistributionPoint" 

626 ) 

627 

628 if reasons and not crl_issuer and not (full_name or relative_name): 

629 raise ValueError( 

630 "You must supply crl_issuer, full_name, or relative_name when " 

631 "reasons is not None" 

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 "<CertificatePolicies({})>".format(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 "<ExtendedKeyUsage({})>".format(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 "<TLSFeature(features={0._features})>".format(self) 

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 "<InhibitAnyPolicy(skip_certs={0.skip_certs})>".format(self) 

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_ip_name(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_ip_name(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_ip_name(self, tree: typing.Iterable[GeneralName]) -> None: 

1315 if any( 

1316 isinstance(name, IPAddress) 

1317 and not isinstance( 

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

1319 ) 

1320 for name in tree 

1321 ): 

1322 raise TypeError( 

1323 "IPAddress name constraints must be an IPv4Network or" 

1324 " IPv6Network object" 

1325 ) 

1326 

1327 def __repr__(self) -> str: 

1328 return ( 

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

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

1331 ) 

1332 

1333 def __hash__(self) -> int: 

1334 if self.permitted_subtrees is not None: 

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

1336 self.permitted_subtrees 

1337 ) 

1338 else: 

1339 ps = None 

1340 

1341 if self.excluded_subtrees is not None: 

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

1343 self.excluded_subtrees 

1344 ) 

1345 else: 

1346 es = None 

1347 

1348 return hash((ps, es)) 

1349 

1350 @property 

1351 def permitted_subtrees( 

1352 self, 

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

1354 return self._permitted_subtrees 

1355 

1356 @property 

1357 def excluded_subtrees( 

1358 self, 

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

1360 return self._excluded_subtrees 

1361 

1362 def public_bytes(self) -> bytes: 

1363 return rust_x509.encode_extension_value(self) 

1364 

1365 

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

1367 def __init__( 

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

1369 ) -> None: 

1370 if not isinstance(oid, ObjectIdentifier): 

1371 raise TypeError( 

1372 "oid argument must be an ObjectIdentifier instance." 

1373 ) 

1374 

1375 if not isinstance(critical, bool): 

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

1377 

1378 self._oid = oid 

1379 self._critical = critical 

1380 self._value = value 

1381 

1382 @property 

1383 def oid(self) -> ObjectIdentifier: 

1384 return self._oid 

1385 

1386 @property 

1387 def critical(self) -> bool: 

1388 return self._critical 

1389 

1390 @property 

1391 def value(self) -> ExtensionTypeVar: 

1392 return self._value 

1393 

1394 def __repr__(self) -> str: 

1395 return ( 

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

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

1398 ).format(self) 

1399 

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

1401 if not isinstance(other, Extension): 

1402 return NotImplemented 

1403 

1404 return ( 

1405 self.oid == other.oid 

1406 and self.critical == other.critical 

1407 and self.value == other.value 

1408 ) 

1409 

1410 def __hash__(self) -> int: 

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

1412 

1413 

1414class GeneralNames: 

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

1416 general_names = list(general_names) 

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

1418 raise TypeError( 

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

1420 "object conforming to the GeneralName interface" 

1421 ) 

1422 

1423 self._general_names = general_names 

1424 

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

1426 

1427 @typing.overload 

1428 def get_values_for_type( 

1429 self, 

1430 type: typing.Union[ 

1431 typing.Type[DNSName], 

1432 typing.Type[UniformResourceIdentifier], 

1433 typing.Type[RFC822Name], 

1434 ], 

1435 ) -> typing.List[str]: 

1436 ... 

1437 

1438 @typing.overload 

1439 def get_values_for_type( 

1440 self, 

1441 type: typing.Type[DirectoryName], 

1442 ) -> typing.List[Name]: 

1443 ... 

1444 

1445 @typing.overload 

1446 def get_values_for_type( 

1447 self, 

1448 type: typing.Type[RegisteredID], 

1449 ) -> typing.List[ObjectIdentifier]: 

1450 ... 

1451 

1452 @typing.overload 

1453 def get_values_for_type( 

1454 self, type: typing.Type[IPAddress] 

1455 ) -> typing.List[_IPADDRESS_TYPES]: 

1456 ... 

1457 

1458 @typing.overload 

1459 def get_values_for_type( 

1460 self, type: typing.Type[OtherName] 

1461 ) -> typing.List[OtherName]: 

1462 ... 

1463 

1464 def get_values_for_type( 

1465 self, 

1466 type: typing.Union[ 

1467 typing.Type[DNSName], 

1468 typing.Type[DirectoryName], 

1469 typing.Type[IPAddress], 

1470 typing.Type[OtherName], 

1471 typing.Type[RFC822Name], 

1472 typing.Type[RegisteredID], 

1473 typing.Type[UniformResourceIdentifier], 

1474 ], 

1475 ) -> typing.Union[ 

1476 typing.List[_IPADDRESS_TYPES], 

1477 typing.List[str], 

1478 typing.List[OtherName], 

1479 typing.List[Name], 

1480 typing.List[ObjectIdentifier], 

1481 ]: 

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

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

1484 # just one value. 

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

1486 if type != OtherName: 

1487 return [i.value for i in objs] 

1488 return list(objs) 

1489 

1490 def __repr__(self) -> str: 

1491 return "<GeneralNames({})>".format(self._general_names) 

1492 

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

1494 if not isinstance(other, GeneralNames): 

1495 return NotImplemented 

1496 

1497 return self._general_names == other._general_names 

1498 

1499 def __hash__(self) -> int: 

1500 return hash(tuple(self._general_names)) 

1501 

1502 

1503class SubjectAlternativeName(ExtensionType): 

1504 oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME 

1505 

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

1507 self._general_names = GeneralNames(general_names) 

1508 

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

1510 

1511 @typing.overload 

1512 def get_values_for_type( 

1513 self, 

1514 type: typing.Union[ 

1515 typing.Type[DNSName], 

1516 typing.Type[UniformResourceIdentifier], 

1517 typing.Type[RFC822Name], 

1518 ], 

1519 ) -> typing.List[str]: 

1520 ... 

1521 

1522 @typing.overload 

1523 def get_values_for_type( 

1524 self, 

1525 type: typing.Type[DirectoryName], 

1526 ) -> typing.List[Name]: 

1527 ... 

1528 

1529 @typing.overload 

1530 def get_values_for_type( 

1531 self, 

1532 type: typing.Type[RegisteredID], 

1533 ) -> typing.List[ObjectIdentifier]: 

1534 ... 

1535 

1536 @typing.overload 

1537 def get_values_for_type( 

1538 self, type: typing.Type[IPAddress] 

1539 ) -> typing.List[_IPADDRESS_TYPES]: 

1540 ... 

1541 

1542 @typing.overload 

1543 def get_values_for_type( 

1544 self, type: typing.Type[OtherName] 

1545 ) -> typing.List[OtherName]: 

1546 ... 

1547 

1548 def get_values_for_type( 

1549 self, 

1550 type: typing.Union[ 

1551 typing.Type[DNSName], 

1552 typing.Type[DirectoryName], 

1553 typing.Type[IPAddress], 

1554 typing.Type[OtherName], 

1555 typing.Type[RFC822Name], 

1556 typing.Type[RegisteredID], 

1557 typing.Type[UniformResourceIdentifier], 

1558 ], 

1559 ) -> typing.Union[ 

1560 typing.List[_IPADDRESS_TYPES], 

1561 typing.List[str], 

1562 typing.List[OtherName], 

1563 typing.List[Name], 

1564 typing.List[ObjectIdentifier], 

1565 ]: 

1566 return self._general_names.get_values_for_type(type) 

1567 

1568 def __repr__(self) -> str: 

1569 return "<SubjectAlternativeName({})>".format(self._general_names) 

1570 

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

1572 if not isinstance(other, SubjectAlternativeName): 

1573 return NotImplemented 

1574 

1575 return self._general_names == other._general_names 

1576 

1577 def __hash__(self) -> int: 

1578 return hash(self._general_names) 

1579 

1580 def public_bytes(self) -> bytes: 

1581 return rust_x509.encode_extension_value(self) 

1582 

1583 

1584class IssuerAlternativeName(ExtensionType): 

1585 oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME 

1586 

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

1588 self._general_names = GeneralNames(general_names) 

1589 

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

1591 

1592 @typing.overload 

1593 def get_values_for_type( 

1594 self, 

1595 type: typing.Union[ 

1596 typing.Type[DNSName], 

1597 typing.Type[UniformResourceIdentifier], 

1598 typing.Type[RFC822Name], 

1599 ], 

1600 ) -> typing.List[str]: 

1601 ... 

1602 

1603 @typing.overload 

1604 def get_values_for_type( 

1605 self, 

1606 type: typing.Type[DirectoryName], 

1607 ) -> typing.List[Name]: 

1608 ... 

1609 

1610 @typing.overload 

1611 def get_values_for_type( 

1612 self, 

1613 type: typing.Type[RegisteredID], 

1614 ) -> typing.List[ObjectIdentifier]: 

1615 ... 

1616 

1617 @typing.overload 

1618 def get_values_for_type( 

1619 self, type: typing.Type[IPAddress] 

1620 ) -> typing.List[_IPADDRESS_TYPES]: 

1621 ... 

1622 

1623 @typing.overload 

1624 def get_values_for_type( 

1625 self, type: typing.Type[OtherName] 

1626 ) -> typing.List[OtherName]: 

1627 ... 

1628 

1629 def get_values_for_type( 

1630 self, 

1631 type: typing.Union[ 

1632 typing.Type[DNSName], 

1633 typing.Type[DirectoryName], 

1634 typing.Type[IPAddress], 

1635 typing.Type[OtherName], 

1636 typing.Type[RFC822Name], 

1637 typing.Type[RegisteredID], 

1638 typing.Type[UniformResourceIdentifier], 

1639 ], 

1640 ) -> typing.Union[ 

1641 typing.List[_IPADDRESS_TYPES], 

1642 typing.List[str], 

1643 typing.List[OtherName], 

1644 typing.List[Name], 

1645 typing.List[ObjectIdentifier], 

1646 ]: 

1647 return self._general_names.get_values_for_type(type) 

1648 

1649 def __repr__(self) -> str: 

1650 return "<IssuerAlternativeName({})>".format(self._general_names) 

1651 

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

1653 if not isinstance(other, IssuerAlternativeName): 

1654 return NotImplemented 

1655 

1656 return self._general_names == other._general_names 

1657 

1658 def __hash__(self) -> int: 

1659 return hash(self._general_names) 

1660 

1661 def public_bytes(self) -> bytes: 

1662 return rust_x509.encode_extension_value(self) 

1663 

1664 

1665class CertificateIssuer(ExtensionType): 

1666 oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER 

1667 

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

1669 self._general_names = GeneralNames(general_names) 

1670 

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

1672 

1673 @typing.overload 

1674 def get_values_for_type( 

1675 self, 

1676 type: typing.Union[ 

1677 typing.Type[DNSName], 

1678 typing.Type[UniformResourceIdentifier], 

1679 typing.Type[RFC822Name], 

1680 ], 

1681 ) -> typing.List[str]: 

1682 ... 

1683 

1684 @typing.overload 

1685 def get_values_for_type( 

1686 self, 

1687 type: typing.Type[DirectoryName], 

1688 ) -> typing.List[Name]: 

1689 ... 

1690 

1691 @typing.overload 

1692 def get_values_for_type( 

1693 self, 

1694 type: typing.Type[RegisteredID], 

1695 ) -> typing.List[ObjectIdentifier]: 

1696 ... 

1697 

1698 @typing.overload 

1699 def get_values_for_type( 

1700 self, type: typing.Type[IPAddress] 

1701 ) -> typing.List[_IPADDRESS_TYPES]: 

1702 ... 

1703 

1704 @typing.overload 

1705 def get_values_for_type( 

1706 self, type: typing.Type[OtherName] 

1707 ) -> typing.List[OtherName]: 

1708 ... 

1709 

1710 def get_values_for_type( 

1711 self, 

1712 type: typing.Union[ 

1713 typing.Type[DNSName], 

1714 typing.Type[DirectoryName], 

1715 typing.Type[IPAddress], 

1716 typing.Type[OtherName], 

1717 typing.Type[RFC822Name], 

1718 typing.Type[RegisteredID], 

1719 typing.Type[UniformResourceIdentifier], 

1720 ], 

1721 ) -> typing.Union[ 

1722 typing.List[_IPADDRESS_TYPES], 

1723 typing.List[str], 

1724 typing.List[OtherName], 

1725 typing.List[Name], 

1726 typing.List[ObjectIdentifier], 

1727 ]: 

1728 return self._general_names.get_values_for_type(type) 

1729 

1730 def __repr__(self) -> str: 

1731 return "<CertificateIssuer({})>".format(self._general_names) 

1732 

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

1734 if not isinstance(other, CertificateIssuer): 

1735 return NotImplemented 

1736 

1737 return self._general_names == other._general_names 

1738 

1739 def __hash__(self) -> int: 

1740 return hash(self._general_names) 

1741 

1742 def public_bytes(self) -> bytes: 

1743 return rust_x509.encode_extension_value(self) 

1744 

1745 

1746class CRLReason(ExtensionType): 

1747 oid = CRLEntryExtensionOID.CRL_REASON 

1748 

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

1750 if not isinstance(reason, ReasonFlags): 

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

1752 

1753 self._reason = reason 

1754 

1755 def __repr__(self) -> str: 

1756 return "<CRLReason(reason={})>".format(self._reason) 

1757 

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

1759 if not isinstance(other, CRLReason): 

1760 return NotImplemented 

1761 

1762 return self.reason == other.reason 

1763 

1764 def __hash__(self) -> int: 

1765 return hash(self.reason) 

1766 

1767 @property 

1768 def reason(self) -> ReasonFlags: 

1769 return self._reason 

1770 

1771 def public_bytes(self) -> bytes: 

1772 return rust_x509.encode_extension_value(self) 

1773 

1774 

1775class InvalidityDate(ExtensionType): 

1776 oid = CRLEntryExtensionOID.INVALIDITY_DATE 

1777 

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

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

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

1781 

1782 self._invalidity_date = invalidity_date 

1783 

1784 def __repr__(self) -> str: 

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

1786 self._invalidity_date 

1787 ) 

1788 

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

1790 if not isinstance(other, InvalidityDate): 

1791 return NotImplemented 

1792 

1793 return self.invalidity_date == other.invalidity_date 

1794 

1795 def __hash__(self) -> int: 

1796 return hash(self.invalidity_date) 

1797 

1798 @property 

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

1800 return self._invalidity_date 

1801 

1802 def public_bytes(self) -> bytes: 

1803 return rust_x509.encode_extension_value(self) 

1804 

1805 

1806class PrecertificateSignedCertificateTimestamps(ExtensionType): 

1807 oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS 

1808 

1809 def __init__( 

1810 self, 

1811 signed_certificate_timestamps: typing.Iterable[ 

1812 SignedCertificateTimestamp 

1813 ], 

1814 ) -> None: 

1815 signed_certificate_timestamps = list(signed_certificate_timestamps) 

1816 if not all( 

1817 isinstance(sct, SignedCertificateTimestamp) 

1818 for sct in signed_certificate_timestamps 

1819 ): 

1820 raise TypeError( 

1821 "Every item in the signed_certificate_timestamps list must be " 

1822 "a SignedCertificateTimestamp" 

1823 ) 

1824 self._signed_certificate_timestamps = signed_certificate_timestamps 

1825 

1826 __len__, __iter__, __getitem__ = _make_sequence_methods( 

1827 "_signed_certificate_timestamps" 

1828 ) 

1829 

1830 def __repr__(self) -> str: 

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

1832 list(self) 

1833 ) 

1834 

1835 def __hash__(self) -> int: 

1836 return hash(tuple(self._signed_certificate_timestamps)) 

1837 

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

1839 if not isinstance(other, PrecertificateSignedCertificateTimestamps): 

1840 return NotImplemented 

1841 

1842 return ( 

1843 self._signed_certificate_timestamps 

1844 == other._signed_certificate_timestamps 

1845 ) 

1846 

1847 def public_bytes(self) -> bytes: 

1848 return rust_x509.encode_extension_value(self) 

1849 

1850 

1851class SignedCertificateTimestamps(ExtensionType): 

1852 oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS 

1853 

1854 def __init__( 

1855 self, 

1856 signed_certificate_timestamps: typing.Iterable[ 

1857 SignedCertificateTimestamp 

1858 ], 

1859 ) -> None: 

1860 signed_certificate_timestamps = list(signed_certificate_timestamps) 

1861 if not all( 

1862 isinstance(sct, SignedCertificateTimestamp) 

1863 for sct in signed_certificate_timestamps 

1864 ): 

1865 raise TypeError( 

1866 "Every item in the signed_certificate_timestamps list must be " 

1867 "a SignedCertificateTimestamp" 

1868 ) 

1869 self._signed_certificate_timestamps = signed_certificate_timestamps 

1870 

1871 __len__, __iter__, __getitem__ = _make_sequence_methods( 

1872 "_signed_certificate_timestamps" 

1873 ) 

1874 

1875 def __repr__(self) -> str: 

1876 return "<SignedCertificateTimestamps({})>".format(list(self)) 

1877 

1878 def __hash__(self) -> int: 

1879 return hash(tuple(self._signed_certificate_timestamps)) 

1880 

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

1882 if not isinstance(other, SignedCertificateTimestamps): 

1883 return NotImplemented 

1884 

1885 return ( 

1886 self._signed_certificate_timestamps 

1887 == other._signed_certificate_timestamps 

1888 ) 

1889 

1890 def public_bytes(self) -> bytes: 

1891 return rust_x509.encode_extension_value(self) 

1892 

1893 

1894class OCSPNonce(ExtensionType): 

1895 oid = OCSPExtensionOID.NONCE 

1896 

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

1898 if not isinstance(nonce, bytes): 

1899 raise TypeError("nonce must be bytes") 

1900 

1901 self._nonce = nonce 

1902 

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

1904 if not isinstance(other, OCSPNonce): 

1905 return NotImplemented 

1906 

1907 return self.nonce == other.nonce 

1908 

1909 def __hash__(self) -> int: 

1910 return hash(self.nonce) 

1911 

1912 def __repr__(self) -> str: 

1913 return "<OCSPNonce(nonce={0.nonce!r})>".format(self) 

1914 

1915 @property 

1916 def nonce(self) -> bytes: 

1917 return self._nonce 

1918 

1919 def public_bytes(self) -> bytes: 

1920 return rust_x509.encode_extension_value(self) 

1921 

1922 

1923class IssuingDistributionPoint(ExtensionType): 

1924 oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT 

1925 

1926 def __init__( 

1927 self, 

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

1929 relative_name: typing.Optional[RelativeDistinguishedName], 

1930 only_contains_user_certs: bool, 

1931 only_contains_ca_certs: bool, 

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

1933 indirect_crl: bool, 

1934 only_contains_attribute_certs: bool, 

1935 ) -> None: 

1936 if full_name is not None: 

1937 full_name = list(full_name) 

1938 

1939 if only_some_reasons and ( 

1940 not isinstance(only_some_reasons, frozenset) 

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

1942 ): 

1943 raise TypeError( 

1944 "only_some_reasons must be None or frozenset of ReasonFlags" 

1945 ) 

1946 

1947 if only_some_reasons and ( 

1948 ReasonFlags.unspecified in only_some_reasons 

1949 or ReasonFlags.remove_from_crl in only_some_reasons 

1950 ): 

1951 raise ValueError( 

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

1953 "IssuingDistributionPoint" 

1954 ) 

1955 

1956 if not ( 

1957 isinstance(only_contains_user_certs, bool) 

1958 and isinstance(only_contains_ca_certs, bool) 

1959 and isinstance(indirect_crl, bool) 

1960 and isinstance(only_contains_attribute_certs, bool) 

1961 ): 

1962 raise TypeError( 

1963 "only_contains_user_certs, only_contains_ca_certs, " 

1964 "indirect_crl and only_contains_attribute_certs " 

1965 "must all be boolean." 

1966 ) 

1967 

1968 crl_constraints = [ 

1969 only_contains_user_certs, 

1970 only_contains_ca_certs, 

1971 indirect_crl, 

1972 only_contains_attribute_certs, 

1973 ] 

1974 

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

1976 raise ValueError( 

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

1978 "only_contains_user_certs, only_contains_ca_certs, " 

1979 "indirect_crl, only_contains_attribute_certs" 

1980 ) 

1981 

1982 if not any( 

1983 [ 

1984 only_contains_user_certs, 

1985 only_contains_ca_certs, 

1986 indirect_crl, 

1987 only_contains_attribute_certs, 

1988 full_name, 

1989 relative_name, 

1990 only_some_reasons, 

1991 ] 

1992 ): 

1993 raise ValueError( 

1994 "Cannot create empty extension: " 

1995 "if only_contains_user_certs, only_contains_ca_certs, " 

1996 "indirect_crl, and only_contains_attribute_certs are all False" 

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

1998 "must have a value." 

1999 ) 

2000 

2001 self._only_contains_user_certs = only_contains_user_certs 

2002 self._only_contains_ca_certs = only_contains_ca_certs 

2003 self._indirect_crl = indirect_crl 

2004 self._only_contains_attribute_certs = only_contains_attribute_certs 

2005 self._only_some_reasons = only_some_reasons 

2006 self._full_name = full_name 

2007 self._relative_name = relative_name 

2008 

2009 def __repr__(self) -> str: 

2010 return ( 

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

2012 "relative_name={0.relative_name}, " 

2013 "only_contains_user_certs={0.only_contains_user_certs}, " 

2014 "only_contains_ca_certs={0.only_contains_ca_certs}, " 

2015 "only_some_reasons={0.only_some_reasons}, " 

2016 "indirect_crl={0.indirect_crl}, " 

2017 "only_contains_attribute_certs=" 

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

2019 ) 

2020 

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

2022 if not isinstance(other, IssuingDistributionPoint): 

2023 return NotImplemented 

2024 

2025 return ( 

2026 self.full_name == other.full_name 

2027 and self.relative_name == other.relative_name 

2028 and self.only_contains_user_certs == other.only_contains_user_certs 

2029 and self.only_contains_ca_certs == other.only_contains_ca_certs 

2030 and self.only_some_reasons == other.only_some_reasons 

2031 and self.indirect_crl == other.indirect_crl 

2032 and self.only_contains_attribute_certs 

2033 == other.only_contains_attribute_certs 

2034 ) 

2035 

2036 def __hash__(self) -> int: 

2037 return hash( 

2038 ( 

2039 self.full_name, 

2040 self.relative_name, 

2041 self.only_contains_user_certs, 

2042 self.only_contains_ca_certs, 

2043 self.only_some_reasons, 

2044 self.indirect_crl, 

2045 self.only_contains_attribute_certs, 

2046 ) 

2047 ) 

2048 

2049 @property 

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

2051 return self._full_name 

2052 

2053 @property 

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

2055 return self._relative_name 

2056 

2057 @property 

2058 def only_contains_user_certs(self) -> bool: 

2059 return self._only_contains_user_certs 

2060 

2061 @property 

2062 def only_contains_ca_certs(self) -> bool: 

2063 return self._only_contains_ca_certs 

2064 

2065 @property 

2066 def only_some_reasons( 

2067 self, 

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

2069 return self._only_some_reasons 

2070 

2071 @property 

2072 def indirect_crl(self) -> bool: 

2073 return self._indirect_crl 

2074 

2075 @property 

2076 def only_contains_attribute_certs(self) -> bool: 

2077 return self._only_contains_attribute_certs 

2078 

2079 def public_bytes(self) -> bytes: 

2080 return rust_x509.encode_extension_value(self) 

2081 

2082 

2083class UnrecognizedExtension(ExtensionType): 

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

2085 if not isinstance(oid, ObjectIdentifier): 

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

2087 self._oid = oid 

2088 self._value = value 

2089 

2090 @property 

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

2092 return self._oid 

2093 

2094 @property 

2095 def value(self) -> bytes: 

2096 return self._value 

2097 

2098 def __repr__(self) -> str: 

2099 return ( 

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

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

2102 ) 

2103 

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

2105 if not isinstance(other, UnrecognizedExtension): 

2106 return NotImplemented 

2107 

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

2109 

2110 def __hash__(self) -> int: 

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

2112 

2113 def public_bytes(self) -> bytes: 

2114 return self.value