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 absolute_import, division, print_function 6 7import abc 8import datetime 9import hashlib 10import ipaddress 11from enum import Enum 12 13from asn1crypto.keys import PublicKeyInfo 14 15import six 16 17from cryptography import utils 18from cryptography.hazmat.primitives import constant_time, serialization 19from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey 20from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey 21from cryptography.x509.certificate_transparency import ( 22 SignedCertificateTimestamp 23) 24from cryptography.x509.general_name import GeneralName, IPAddress, OtherName 25from cryptography.x509.name import RelativeDistinguishedName 26from cryptography.x509.oid import ( 27 CRLEntryExtensionOID, ExtensionOID, OCSPExtensionOID, ObjectIdentifier, 28) 29 30 31def _key_identifier_from_public_key(public_key): 32 if isinstance(public_key, RSAPublicKey): 33 data = public_key.public_bytes( 34 serialization.Encoding.DER, 35 serialization.PublicFormat.PKCS1, 36 ) 37 elif isinstance(public_key, EllipticCurvePublicKey): 38 data = public_key.public_bytes( 39 serialization.Encoding.X962, 40 serialization.PublicFormat.UncompressedPoint 41 ) 42 else: 43 # This is a very slow way to do this. 44 serialized = public_key.public_bytes( 45 serialization.Encoding.DER, 46 serialization.PublicFormat.SubjectPublicKeyInfo 47 ) 48 49 data = bytes(PublicKeyInfo.load(serialized)['public_key']) 50 51 return hashlib.sha1(data).digest() 52 53 54class DuplicateExtension(Exception): 55 def __init__(self, msg, oid): 56 super(DuplicateExtension, self).__init__(msg) 57 self.oid = oid 58 59 60class ExtensionNotFound(Exception): 61 def __init__(self, msg, oid): 62 super(ExtensionNotFound, self).__init__(msg) 63 self.oid = oid 64 65 66@six.add_metaclass(abc.ABCMeta) 67class ExtensionType(object): 68 @abc.abstractproperty 69 def oid(self): 70 """ 71 Returns the oid associated with the given extension type. 72 """ 73 74 75class Extensions(object): 76 def __init__(self, extensions): 77 self._extensions = extensions 78 79 def get_extension_for_oid(self, oid): 80 for ext in self: 81 if ext.oid == oid: 82 return ext 83 84 raise ExtensionNotFound("No {0} extension was found".format(oid), oid) 85 86 def get_extension_for_class(self, extclass): 87 if extclass is UnrecognizedExtension: 88 raise TypeError( 89 "UnrecognizedExtension can't be used with " 90 "get_extension_for_class because more than one instance of the" 91 " class may be present." 92 ) 93 94 for ext in self: 95 if isinstance(ext.value, extclass): 96 return ext 97 98 raise ExtensionNotFound( 99 "No {0} extension was found".format(extclass), extclass.oid 100 ) 101 102 def __iter__(self): 103 return iter(self._extensions) 104 105 def __len__(self): 106 return len(self._extensions) 107 108 def __getitem__(self, idx): 109 return self._extensions[idx] 110 111 def __repr__(self): 112 return ( 113 "<Extensions({0})>".format(self._extensions) 114 ) 115 116 117@utils.register_interface(ExtensionType) 118class CRLNumber(object): 119 oid = ExtensionOID.CRL_NUMBER 120 121 def __init__(self, crl_number): 122 if not isinstance(crl_number, six.integer_types): 123 raise TypeError("crl_number must be an integer") 124 125 self._crl_number = crl_number 126 127 def __eq__(self, other): 128 if not isinstance(other, CRLNumber): 129 return NotImplemented 130 131 return self.crl_number == other.crl_number 132 133 def __ne__(self, other): 134 return not self == other 135 136 def __hash__(self): 137 return hash(self.crl_number) 138 139 def __repr__(self): 140 return "<CRLNumber({0})>".format(self.crl_number) 141 142 crl_number = utils.read_only_property("_crl_number") 143 144 145@utils.register_interface(ExtensionType) 146class AuthorityKeyIdentifier(object): 147 oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER 148 149 def __init__(self, key_identifier, authority_cert_issuer, 150 authority_cert_serial_number): 151 if (authority_cert_issuer is None) != ( 152 authority_cert_serial_number is None 153 ): 154 raise ValueError( 155 "authority_cert_issuer and authority_cert_serial_number " 156 "must both be present or both None" 157 ) 158 159 if authority_cert_issuer is not None: 160 authority_cert_issuer = list(authority_cert_issuer) 161 if not all( 162 isinstance(x, GeneralName) for x in authority_cert_issuer 163 ): 164 raise TypeError( 165 "authority_cert_issuer must be a list of GeneralName " 166 "objects" 167 ) 168 169 if authority_cert_serial_number is not None and not isinstance( 170 authority_cert_serial_number, six.integer_types 171 ): 172 raise TypeError( 173 "authority_cert_serial_number must be an integer" 174 ) 175 176 self._key_identifier = key_identifier 177 self._authority_cert_issuer = authority_cert_issuer 178 self._authority_cert_serial_number = authority_cert_serial_number 179 180 @classmethod 181 def from_issuer_public_key(cls, public_key): 182 digest = _key_identifier_from_public_key(public_key) 183 return cls( 184 key_identifier=digest, 185 authority_cert_issuer=None, 186 authority_cert_serial_number=None 187 ) 188 189 @classmethod 190 def from_issuer_subject_key_identifier(cls, ski): 191 return cls( 192 key_identifier=ski.value.digest, 193 authority_cert_issuer=None, 194 authority_cert_serial_number=None 195 ) 196 197 def __repr__(self): 198 return ( 199 "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, " 200 "authority_cert_issuer={0.authority_cert_issuer}, " 201 "authority_cert_serial_number={0.authority_cert_serial_number}" 202 ")>".format(self) 203 ) 204 205 def __eq__(self, other): 206 if not isinstance(other, AuthorityKeyIdentifier): 207 return NotImplemented 208 209 return ( 210 self.key_identifier == other.key_identifier and 211 self.authority_cert_issuer == other.authority_cert_issuer and 212 self.authority_cert_serial_number == 213 other.authority_cert_serial_number 214 ) 215 216 def __ne__(self, other): 217 return not self == other 218 219 def __hash__(self): 220 if self.authority_cert_issuer is None: 221 aci = None 222 else: 223 aci = tuple(self.authority_cert_issuer) 224 return hash(( 225 self.key_identifier, aci, self.authority_cert_serial_number 226 )) 227 228 key_identifier = utils.read_only_property("_key_identifier") 229 authority_cert_issuer = utils.read_only_property("_authority_cert_issuer") 230 authority_cert_serial_number = utils.read_only_property( 231 "_authority_cert_serial_number" 232 ) 233 234 235@utils.register_interface(ExtensionType) 236class SubjectKeyIdentifier(object): 237 oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER 238 239 def __init__(self, digest): 240 self._digest = digest 241 242 @classmethod 243 def from_public_key(cls, public_key): 244 return cls(_key_identifier_from_public_key(public_key)) 245 246 digest = utils.read_only_property("_digest") 247 248 def __repr__(self): 249 return "<SubjectKeyIdentifier(digest={0!r})>".format(self.digest) 250 251 def __eq__(self, other): 252 if not isinstance(other, SubjectKeyIdentifier): 253 return NotImplemented 254 255 return constant_time.bytes_eq(self.digest, other.digest) 256 257 def __ne__(self, other): 258 return not self == other 259 260 def __hash__(self): 261 return hash(self.digest) 262 263 264@utils.register_interface(ExtensionType) 265class AuthorityInformationAccess(object): 266 oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS 267 268 def __init__(self, descriptions): 269 descriptions = list(descriptions) 270 if not all(isinstance(x, AccessDescription) for x in descriptions): 271 raise TypeError( 272 "Every item in the descriptions list must be an " 273 "AccessDescription" 274 ) 275 276 self._descriptions = descriptions 277 278 def __iter__(self): 279 return iter(self._descriptions) 280 281 def __len__(self): 282 return len(self._descriptions) 283 284 def __repr__(self): 285 return "<AuthorityInformationAccess({0})>".format(self._descriptions) 286 287 def __eq__(self, other): 288 if not isinstance(other, AuthorityInformationAccess): 289 return NotImplemented 290 291 return self._descriptions == other._descriptions 292 293 def __ne__(self, other): 294 return not self == other 295 296 def __getitem__(self, idx): 297 return self._descriptions[idx] 298 299 def __hash__(self): 300 return hash(tuple(self._descriptions)) 301 302 303class AccessDescription(object): 304 def __init__(self, access_method, access_location): 305 if not isinstance(access_method, ObjectIdentifier): 306 raise TypeError("access_method must be an ObjectIdentifier") 307 308 if not isinstance(access_location, GeneralName): 309 raise TypeError("access_location must be a GeneralName") 310 311 self._access_method = access_method 312 self._access_location = access_location 313 314 def __repr__(self): 315 return ( 316 "<AccessDescription(access_method={0.access_method}, access_locati" 317 "on={0.access_location})>".format(self) 318 ) 319 320 def __eq__(self, other): 321 if not isinstance(other, AccessDescription): 322 return NotImplemented 323 324 return ( 325 self.access_method == other.access_method and 326 self.access_location == other.access_location 327 ) 328 329 def __ne__(self, other): 330 return not self == other 331 332 def __hash__(self): 333 return hash((self.access_method, self.access_location)) 334 335 access_method = utils.read_only_property("_access_method") 336 access_location = utils.read_only_property("_access_location") 337 338 339@utils.register_interface(ExtensionType) 340class BasicConstraints(object): 341 oid = ExtensionOID.BASIC_CONSTRAINTS 342 343 def __init__(self, ca, path_length): 344 if not isinstance(ca, bool): 345 raise TypeError("ca must be a boolean value") 346 347 if path_length is not None and not ca: 348 raise ValueError("path_length must be None when ca is False") 349 350 if ( 351 path_length is not None and 352 (not isinstance(path_length, six.integer_types) or path_length < 0) 353 ): 354 raise TypeError( 355 "path_length must be a non-negative integer or None" 356 ) 357 358 self._ca = ca 359 self._path_length = path_length 360 361 ca = utils.read_only_property("_ca") 362 path_length = utils.read_only_property("_path_length") 363 364 def __repr__(self): 365 return ("<BasicConstraints(ca={0.ca}, " 366 "path_length={0.path_length})>").format(self) 367 368 def __eq__(self, other): 369 if not isinstance(other, BasicConstraints): 370 return NotImplemented 371 372 return self.ca == other.ca and self.path_length == other.path_length 373 374 def __ne__(self, other): 375 return not self == other 376 377 def __hash__(self): 378 return hash((self.ca, self.path_length)) 379 380 381@utils.register_interface(ExtensionType) 382class DeltaCRLIndicator(object): 383 oid = ExtensionOID.DELTA_CRL_INDICATOR 384 385 def __init__(self, crl_number): 386 if not isinstance(crl_number, six.integer_types): 387 raise TypeError("crl_number must be an integer") 388 389 self._crl_number = crl_number 390 391 crl_number = utils.read_only_property("_crl_number") 392 393 def __eq__(self, other): 394 if not isinstance(other, DeltaCRLIndicator): 395 return NotImplemented 396 397 return self.crl_number == other.crl_number 398 399 def __ne__(self, other): 400 return not self == other 401 402 def __hash__(self): 403 return hash(self.crl_number) 404 405 def __repr__(self): 406 return "<DeltaCRLIndicator(crl_number={0.crl_number})>".format(self) 407 408 409@utils.register_interface(ExtensionType) 410class CRLDistributionPoints(object): 411 oid = ExtensionOID.CRL_DISTRIBUTION_POINTS 412 413 def __init__(self, distribution_points): 414 distribution_points = list(distribution_points) 415 if not all( 416 isinstance(x, DistributionPoint) for x in distribution_points 417 ): 418 raise TypeError( 419 "distribution_points must be a list of DistributionPoint " 420 "objects" 421 ) 422 423 self._distribution_points = distribution_points 424 425 def __iter__(self): 426 return iter(self._distribution_points) 427 428 def __len__(self): 429 return len(self._distribution_points) 430 431 def __repr__(self): 432 return "<CRLDistributionPoints({0})>".format(self._distribution_points) 433 434 def __eq__(self, other): 435 if not isinstance(other, CRLDistributionPoints): 436 return NotImplemented 437 438 return self._distribution_points == other._distribution_points 439 440 def __ne__(self, other): 441 return not self == other 442 443 def __getitem__(self, idx): 444 return self._distribution_points[idx] 445 446 def __hash__(self): 447 return hash(tuple(self._distribution_points)) 448 449 450@utils.register_interface(ExtensionType) 451class FreshestCRL(object): 452 oid = ExtensionOID.FRESHEST_CRL 453 454 def __init__(self, distribution_points): 455 distribution_points = list(distribution_points) 456 if not all( 457 isinstance(x, DistributionPoint) for x in distribution_points 458 ): 459 raise TypeError( 460 "distribution_points must be a list of DistributionPoint " 461 "objects" 462 ) 463 464 self._distribution_points = distribution_points 465 466 def __iter__(self): 467 return iter(self._distribution_points) 468 469 def __len__(self): 470 return len(self._distribution_points) 471 472 def __repr__(self): 473 return "<FreshestCRL({0})>".format(self._distribution_points) 474 475 def __eq__(self, other): 476 if not isinstance(other, FreshestCRL): 477 return NotImplemented 478 479 return self._distribution_points == other._distribution_points 480 481 def __ne__(self, other): 482 return not self == other 483 484 def __getitem__(self, idx): 485 return self._distribution_points[idx] 486 487 def __hash__(self): 488 return hash(tuple(self._distribution_points)) 489 490 491class DistributionPoint(object): 492 def __init__(self, full_name, relative_name, reasons, crl_issuer): 493 if full_name and relative_name: 494 raise ValueError( 495 "You cannot provide both full_name and relative_name, at " 496 "least one must be None." 497 ) 498 499 if full_name: 500 full_name = list(full_name) 501 if not all(isinstance(x, GeneralName) for x in full_name): 502 raise TypeError( 503 "full_name must be a list of GeneralName objects" 504 ) 505 506 if relative_name: 507 if not isinstance(relative_name, RelativeDistinguishedName): 508 raise TypeError( 509 "relative_name must be a RelativeDistinguishedName" 510 ) 511 512 if crl_issuer: 513 crl_issuer = list(crl_issuer) 514 if not all(isinstance(x, GeneralName) for x in crl_issuer): 515 raise TypeError( 516 "crl_issuer must be None or a list of general names" 517 ) 518 519 if reasons and (not isinstance(reasons, frozenset) or not all( 520 isinstance(x, ReasonFlags) for x in reasons 521 )): 522 raise TypeError("reasons must be None or frozenset of ReasonFlags") 523 524 if reasons and ( 525 ReasonFlags.unspecified in reasons or 526 ReasonFlags.remove_from_crl in reasons 527 ): 528 raise ValueError( 529 "unspecified and remove_from_crl are not valid reasons in a " 530 "DistributionPoint" 531 ) 532 533 if reasons and not crl_issuer and not (full_name or relative_name): 534 raise ValueError( 535 "You must supply crl_issuer, full_name, or relative_name when " 536 "reasons is not None" 537 ) 538 539 self._full_name = full_name 540 self._relative_name = relative_name 541 self._reasons = reasons 542 self._crl_issuer = crl_issuer 543 544 def __repr__(self): 545 return ( 546 "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela" 547 "tive_name}, reasons={0.reasons}, crl_issuer={0.crl_issuer})>" 548 .format(self) 549 ) 550 551 def __eq__(self, other): 552 if not isinstance(other, DistributionPoint): 553 return NotImplemented 554 555 return ( 556 self.full_name == other.full_name and 557 self.relative_name == other.relative_name and 558 self.reasons == other.reasons and 559 self.crl_issuer == other.crl_issuer 560 ) 561 562 def __ne__(self, other): 563 return not self == other 564 565 def __hash__(self): 566 if self.full_name is not None: 567 fn = tuple(self.full_name) 568 else: 569 fn = None 570 571 if self.crl_issuer is not None: 572 crl_issuer = tuple(self.crl_issuer) 573 else: 574 crl_issuer = None 575 576 return hash((fn, self.relative_name, self.reasons, crl_issuer)) 577 578 full_name = utils.read_only_property("_full_name") 579 relative_name = utils.read_only_property("_relative_name") 580 reasons = utils.read_only_property("_reasons") 581 crl_issuer = utils.read_only_property("_crl_issuer") 582 583 584class ReasonFlags(Enum): 585 unspecified = "unspecified" 586 key_compromise = "keyCompromise" 587 ca_compromise = "cACompromise" 588 affiliation_changed = "affiliationChanged" 589 superseded = "superseded" 590 cessation_of_operation = "cessationOfOperation" 591 certificate_hold = "certificateHold" 592 privilege_withdrawn = "privilegeWithdrawn" 593 aa_compromise = "aACompromise" 594 remove_from_crl = "removeFromCRL" 595 596 597@utils.register_interface(ExtensionType) 598class PolicyConstraints(object): 599 oid = ExtensionOID.POLICY_CONSTRAINTS 600 601 def __init__(self, require_explicit_policy, inhibit_policy_mapping): 602 if require_explicit_policy is not None and not isinstance( 603 require_explicit_policy, six.integer_types 604 ): 605 raise TypeError( 606 "require_explicit_policy must be a non-negative integer or " 607 "None" 608 ) 609 610 if inhibit_policy_mapping is not None and not isinstance( 611 inhibit_policy_mapping, six.integer_types 612 ): 613 raise TypeError( 614 "inhibit_policy_mapping must be a non-negative integer or None" 615 ) 616 617 if inhibit_policy_mapping is None and require_explicit_policy is None: 618 raise ValueError( 619 "At least one of require_explicit_policy and " 620 "inhibit_policy_mapping must not be None" 621 ) 622 623 self._require_explicit_policy = require_explicit_policy 624 self._inhibit_policy_mapping = inhibit_policy_mapping 625 626 def __repr__(self): 627 return ( 628 u"<PolicyConstraints(require_explicit_policy={0.require_explicit" 629 u"_policy}, inhibit_policy_mapping={0.inhibit_policy_" 630 u"mapping})>".format(self) 631 ) 632 633 def __eq__(self, other): 634 if not isinstance(other, PolicyConstraints): 635 return NotImplemented 636 637 return ( 638 self.require_explicit_policy == other.require_explicit_policy and 639 self.inhibit_policy_mapping == other.inhibit_policy_mapping 640 ) 641 642 def __ne__(self, other): 643 return not self == other 644 645 def __hash__(self): 646 return hash( 647 (self.require_explicit_policy, self.inhibit_policy_mapping) 648 ) 649 650 require_explicit_policy = utils.read_only_property( 651 "_require_explicit_policy" 652 ) 653 inhibit_policy_mapping = utils.read_only_property( 654 "_inhibit_policy_mapping" 655 ) 656 657 658@utils.register_interface(ExtensionType) 659class CertificatePolicies(object): 660 oid = ExtensionOID.CERTIFICATE_POLICIES 661 662 def __init__(self, policies): 663 policies = list(policies) 664 if not all(isinstance(x, PolicyInformation) for x in policies): 665 raise TypeError( 666 "Every item in the policies list must be a " 667 "PolicyInformation" 668 ) 669 670 self._policies = policies 671 672 def __iter__(self): 673 return iter(self._policies) 674 675 def __len__(self): 676 return len(self._policies) 677 678 def __repr__(self): 679 return "<CertificatePolicies({0})>".format(self._policies) 680 681 def __eq__(self, other): 682 if not isinstance(other, CertificatePolicies): 683 return NotImplemented 684 685 return self._policies == other._policies 686 687 def __ne__(self, other): 688 return not self == other 689 690 def __getitem__(self, idx): 691 return self._policies[idx] 692 693 def __hash__(self): 694 return hash(tuple(self._policies)) 695 696 697class PolicyInformation(object): 698 def __init__(self, policy_identifier, policy_qualifiers): 699 if not isinstance(policy_identifier, ObjectIdentifier): 700 raise TypeError("policy_identifier must be an ObjectIdentifier") 701 702 self._policy_identifier = policy_identifier 703 704 if policy_qualifiers: 705 policy_qualifiers = list(policy_qualifiers) 706 if not all( 707 isinstance(x, (six.text_type, UserNotice)) 708 for x in policy_qualifiers 709 ): 710 raise TypeError( 711 "policy_qualifiers must be a list of strings and/or " 712 "UserNotice objects or None" 713 ) 714 715 self._policy_qualifiers = policy_qualifiers 716 717 def __repr__(self): 718 return ( 719 "<PolicyInformation(policy_identifier={0.policy_identifier}, polic" 720 "y_qualifiers={0.policy_qualifiers})>".format(self) 721 ) 722 723 def __eq__(self, other): 724 if not isinstance(other, PolicyInformation): 725 return NotImplemented 726 727 return ( 728 self.policy_identifier == other.policy_identifier and 729 self.policy_qualifiers == other.policy_qualifiers 730 ) 731 732 def __ne__(self, other): 733 return not self == other 734 735 def __hash__(self): 736 if self.policy_qualifiers is not None: 737 pq = tuple(self.policy_qualifiers) 738 else: 739 pq = None 740 741 return hash((self.policy_identifier, pq)) 742 743 policy_identifier = utils.read_only_property("_policy_identifier") 744 policy_qualifiers = utils.read_only_property("_policy_qualifiers") 745 746 747class UserNotice(object): 748 def __init__(self, notice_reference, explicit_text): 749 if notice_reference and not isinstance( 750 notice_reference, NoticeReference 751 ): 752 raise TypeError( 753 "notice_reference must be None or a NoticeReference" 754 ) 755 756 self._notice_reference = notice_reference 757 self._explicit_text = explicit_text 758 759 def __repr__(self): 760 return ( 761 "<UserNotice(notice_reference={0.notice_reference}, explicit_text=" 762 "{0.explicit_text!r})>".format(self) 763 ) 764 765 def __eq__(self, other): 766 if not isinstance(other, UserNotice): 767 return NotImplemented 768 769 return ( 770 self.notice_reference == other.notice_reference and 771 self.explicit_text == other.explicit_text 772 ) 773 774 def __ne__(self, other): 775 return not self == other 776 777 def __hash__(self): 778 return hash((self.notice_reference, self.explicit_text)) 779 780 notice_reference = utils.read_only_property("_notice_reference") 781 explicit_text = utils.read_only_property("_explicit_text") 782 783 784class NoticeReference(object): 785 def __init__(self, organization, notice_numbers): 786 self._organization = organization 787 notice_numbers = list(notice_numbers) 788 if not all(isinstance(x, int) for x in notice_numbers): 789 raise TypeError( 790 "notice_numbers must be a list of integers" 791 ) 792 793 self._notice_numbers = notice_numbers 794 795 def __repr__(self): 796 return ( 797 "<NoticeReference(organization={0.organization!r}, notice_numbers=" 798 "{0.notice_numbers})>".format(self) 799 ) 800 801 def __eq__(self, other): 802 if not isinstance(other, NoticeReference): 803 return NotImplemented 804 805 return ( 806 self.organization == other.organization and 807 self.notice_numbers == other.notice_numbers 808 ) 809 810 def __ne__(self, other): 811 return not self == other 812 813 def __hash__(self): 814 return hash((self.organization, tuple(self.notice_numbers))) 815 816 organization = utils.read_only_property("_organization") 817 notice_numbers = utils.read_only_property("_notice_numbers") 818 819 820@utils.register_interface(ExtensionType) 821class ExtendedKeyUsage(object): 822 oid = ExtensionOID.EXTENDED_KEY_USAGE 823 824 def __init__(self, usages): 825 usages = list(usages) 826 if not all(isinstance(x, ObjectIdentifier) for x in usages): 827 raise TypeError( 828 "Every item in the usages list must be an ObjectIdentifier" 829 ) 830 831 self._usages = usages 832 833 def __iter__(self): 834 return iter(self._usages) 835 836 def __len__(self): 837 return len(self._usages) 838 839 def __repr__(self): 840 return "<ExtendedKeyUsage({0})>".format(self._usages) 841 842 def __eq__(self, other): 843 if not isinstance(other, ExtendedKeyUsage): 844 return NotImplemented 845 846 return self._usages == other._usages 847 848 def __ne__(self, other): 849 return not self == other 850 851 def __hash__(self): 852 return hash(tuple(self._usages)) 853 854 855@utils.register_interface(ExtensionType) 856class OCSPNoCheck(object): 857 oid = ExtensionOID.OCSP_NO_CHECK 858 859 860@utils.register_interface(ExtensionType) 861class PrecertPoison(object): 862 oid = ExtensionOID.PRECERT_POISON 863 864 865@utils.register_interface(ExtensionType) 866class TLSFeature(object): 867 oid = ExtensionOID.TLS_FEATURE 868 869 def __init__(self, features): 870 features = list(features) 871 if ( 872 not all(isinstance(x, TLSFeatureType) for x in features) or 873 len(features) == 0 874 ): 875 raise TypeError( 876 "features must be a list of elements from the TLSFeatureType " 877 "enum" 878 ) 879 880 self._features = features 881 882 def __iter__(self): 883 return iter(self._features) 884 885 def __len__(self): 886 return len(self._features) 887 888 def __repr__(self): 889 return "<TLSFeature(features={0._features})>".format(self) 890 891 def __eq__(self, other): 892 if not isinstance(other, TLSFeature): 893 return NotImplemented 894 895 return self._features == other._features 896 897 def __getitem__(self, idx): 898 return self._features[idx] 899 900 def __ne__(self, other): 901 return not self == other 902 903 def __hash__(self): 904 return hash(tuple(self._features)) 905 906 907class TLSFeatureType(Enum): 908 # status_request is defined in RFC 6066 and is used for what is commonly 909 # called OCSP Must-Staple when present in the TLS Feature extension in an 910 # X.509 certificate. 911 status_request = 5 912 # status_request_v2 is defined in RFC 6961 and allows multiple OCSP 913 # responses to be provided. It is not currently in use by clients or 914 # servers. 915 status_request_v2 = 17 916 917 918_TLS_FEATURE_TYPE_TO_ENUM = dict((x.value, x) for x in TLSFeatureType) 919 920 921@utils.register_interface(ExtensionType) 922class InhibitAnyPolicy(object): 923 oid = ExtensionOID.INHIBIT_ANY_POLICY 924 925 def __init__(self, skip_certs): 926 if not isinstance(skip_certs, six.integer_types): 927 raise TypeError("skip_certs must be an integer") 928 929 if skip_certs < 0: 930 raise ValueError("skip_certs must be a non-negative integer") 931 932 self._skip_certs = skip_certs 933 934 def __repr__(self): 935 return "<InhibitAnyPolicy(skip_certs={0.skip_certs})>".format(self) 936 937 def __eq__(self, other): 938 if not isinstance(other, InhibitAnyPolicy): 939 return NotImplemented 940 941 return self.skip_certs == other.skip_certs 942 943 def __ne__(self, other): 944 return not self == other 945 946 def __hash__(self): 947 return hash(self.skip_certs) 948 949 skip_certs = utils.read_only_property("_skip_certs") 950 951 952@utils.register_interface(ExtensionType) 953class KeyUsage(object): 954 oid = ExtensionOID.KEY_USAGE 955 956 def __init__(self, digital_signature, content_commitment, key_encipherment, 957 data_encipherment, key_agreement, key_cert_sign, crl_sign, 958 encipher_only, decipher_only): 959 if not key_agreement and (encipher_only or decipher_only): 960 raise ValueError( 961 "encipher_only and decipher_only can only be true when " 962 "key_agreement is true" 963 ) 964 965 self._digital_signature = digital_signature 966 self._content_commitment = content_commitment 967 self._key_encipherment = key_encipherment 968 self._data_encipherment = data_encipherment 969 self._key_agreement = key_agreement 970 self._key_cert_sign = key_cert_sign 971 self._crl_sign = crl_sign 972 self._encipher_only = encipher_only 973 self._decipher_only = decipher_only 974 975 digital_signature = utils.read_only_property("_digital_signature") 976 content_commitment = utils.read_only_property("_content_commitment") 977 key_encipherment = utils.read_only_property("_key_encipherment") 978 data_encipherment = utils.read_only_property("_data_encipherment") 979 key_agreement = utils.read_only_property("_key_agreement") 980 key_cert_sign = utils.read_only_property("_key_cert_sign") 981 crl_sign = utils.read_only_property("_crl_sign") 982 983 @property 984 def encipher_only(self): 985 if not self.key_agreement: 986 raise ValueError( 987 "encipher_only is undefined unless key_agreement is true" 988 ) 989 else: 990 return self._encipher_only 991 992 @property 993 def decipher_only(self): 994 if not self.key_agreement: 995 raise ValueError( 996 "decipher_only is undefined unless key_agreement is true" 997 ) 998 else: 999 return self._decipher_only 1000 1001 def __repr__(self): 1002 try: 1003 encipher_only = self.encipher_only 1004 decipher_only = self.decipher_only 1005 except ValueError: 1006 encipher_only = None 1007 decipher_only = None 1008 1009 return ("<KeyUsage(digital_signature={0.digital_signature}, " 1010 "content_commitment={0.content_commitment}, " 1011 "key_encipherment={0.key_encipherment}, " 1012 "data_encipherment={0.data_encipherment}, " 1013 "key_agreement={0.key_agreement}, " 1014 "key_cert_sign={0.key_cert_sign}, crl_sign={0.crl_sign}, " 1015 "encipher_only={1}, decipher_only={2})>").format( 1016 self, encipher_only, decipher_only) 1017 1018 def __eq__(self, other): 1019 if not isinstance(other, KeyUsage): 1020 return NotImplemented 1021 1022 return ( 1023 self.digital_signature == other.digital_signature and 1024 self.content_commitment == other.content_commitment and 1025 self.key_encipherment == other.key_encipherment and 1026 self.data_encipherment == other.data_encipherment and 1027 self.key_agreement == other.key_agreement and 1028 self.key_cert_sign == other.key_cert_sign and 1029 self.crl_sign == other.crl_sign and 1030 self._encipher_only == other._encipher_only and 1031 self._decipher_only == other._decipher_only 1032 ) 1033 1034 def __ne__(self, other): 1035 return not self == other 1036 1037 def __hash__(self): 1038 return hash(( 1039 self.digital_signature, self.content_commitment, 1040 self.key_encipherment, self.data_encipherment, 1041 self.key_agreement, self.key_cert_sign, 1042 self.crl_sign, self._encipher_only, 1043 self._decipher_only 1044 )) 1045 1046 1047@utils.register_interface(ExtensionType) 1048class NameConstraints(object): 1049 oid = ExtensionOID.NAME_CONSTRAINTS 1050 1051 def __init__(self, permitted_subtrees, excluded_subtrees): 1052 if permitted_subtrees is not None: 1053 permitted_subtrees = list(permitted_subtrees) 1054 if not all( 1055 isinstance(x, GeneralName) for x in permitted_subtrees 1056 ): 1057 raise TypeError( 1058 "permitted_subtrees must be a list of GeneralName objects " 1059 "or None" 1060 ) 1061 1062 self._validate_ip_name(permitted_subtrees) 1063 1064 if excluded_subtrees is not None: 1065 excluded_subtrees = list(excluded_subtrees) 1066 if not all( 1067 isinstance(x, GeneralName) for x in excluded_subtrees 1068 ): 1069 raise TypeError( 1070 "excluded_subtrees must be a list of GeneralName objects " 1071 "or None" 1072 ) 1073 1074 self._validate_ip_name(excluded_subtrees) 1075 1076 if permitted_subtrees is None and excluded_subtrees is None: 1077 raise ValueError( 1078 "At least one of permitted_subtrees and excluded_subtrees " 1079 "must not be None" 1080 ) 1081 1082 self._permitted_subtrees = permitted_subtrees 1083 self._excluded_subtrees = excluded_subtrees 1084 1085 def __eq__(self, other): 1086 if not isinstance(other, NameConstraints): 1087 return NotImplemented 1088 1089 return ( 1090 self.excluded_subtrees == other.excluded_subtrees and 1091 self.permitted_subtrees == other.permitted_subtrees 1092 ) 1093 1094 def __ne__(self, other): 1095 return not self == other 1096 1097 def _validate_ip_name(self, tree): 1098 if any(isinstance(name, IPAddress) and not isinstance( 1099 name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network) 1100 ) for name in tree): 1101 raise TypeError( 1102 "IPAddress name constraints must be an IPv4Network or" 1103 " IPv6Network object" 1104 ) 1105 1106 def __repr__(self): 1107 return ( 1108 u"<NameConstraints(permitted_subtrees={0.permitted_subtrees}, " 1109 u"excluded_subtrees={0.excluded_subtrees})>".format(self) 1110 ) 1111 1112 def __hash__(self): 1113 if self.permitted_subtrees is not None: 1114 ps = tuple(self.permitted_subtrees) 1115 else: 1116 ps = None 1117 1118 if self.excluded_subtrees is not None: 1119 es = tuple(self.excluded_subtrees) 1120 else: 1121 es = None 1122 1123 return hash((ps, es)) 1124 1125 permitted_subtrees = utils.read_only_property("_permitted_subtrees") 1126 excluded_subtrees = utils.read_only_property("_excluded_subtrees") 1127 1128 1129class Extension(object): 1130 def __init__(self, oid, critical, value): 1131 if not isinstance(oid, ObjectIdentifier): 1132 raise TypeError( 1133 "oid argument must be an ObjectIdentifier instance." 1134 ) 1135 1136 if not isinstance(critical, bool): 1137 raise TypeError("critical must be a boolean value") 1138 1139 self._oid = oid 1140 self._critical = critical 1141 self._value = value 1142 1143 oid = utils.read_only_property("_oid") 1144 critical = utils.read_only_property("_critical") 1145 value = utils.read_only_property("_value") 1146 1147 def __repr__(self): 1148 return ("<Extension(oid={0.oid}, critical={0.critical}, " 1149 "value={0.value})>").format(self) 1150 1151 def __eq__(self, other): 1152 if not isinstance(other, Extension): 1153 return NotImplemented 1154 1155 return ( 1156 self.oid == other.oid and 1157 self.critical == other.critical and 1158 self.value == other.value 1159 ) 1160 1161 def __ne__(self, other): 1162 return not self == other 1163 1164 def __hash__(self): 1165 return hash((self.oid, self.critical, self.value)) 1166 1167 1168class GeneralNames(object): 1169 def __init__(self, general_names): 1170 general_names = list(general_names) 1171 if not all(isinstance(x, GeneralName) for x in general_names): 1172 raise TypeError( 1173 "Every item in the general_names list must be an " 1174 "object conforming to the GeneralName interface" 1175 ) 1176 1177 self._general_names = general_names 1178 1179 def __iter__(self): 1180 return iter(self._general_names) 1181 1182 def __len__(self): 1183 return len(self._general_names) 1184 1185 def get_values_for_type(self, type): 1186 # Return the value of each GeneralName, except for OtherName instances 1187 # which we return directly because it has two important properties not 1188 # just one value. 1189 objs = (i for i in self if isinstance(i, type)) 1190 if type != OtherName: 1191 objs = (i.value for i in objs) 1192 return list(objs) 1193 1194 def __repr__(self): 1195 return "<GeneralNames({0})>".format(self._general_names) 1196 1197 def __eq__(self, other): 1198 if not isinstance(other, GeneralNames): 1199 return NotImplemented 1200 1201 return self._general_names == other._general_names 1202 1203 def __ne__(self, other): 1204 return not self == other 1205 1206 def __getitem__(self, idx): 1207 return self._general_names[idx] 1208 1209 def __hash__(self): 1210 return hash(tuple(self._general_names)) 1211 1212 1213@utils.register_interface(ExtensionType) 1214class SubjectAlternativeName(object): 1215 oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME 1216 1217 def __init__(self, general_names): 1218 self._general_names = GeneralNames(general_names) 1219 1220 def __iter__(self): 1221 return iter(self._general_names) 1222 1223 def __len__(self): 1224 return len(self._general_names) 1225 1226 def get_values_for_type(self, type): 1227 return self._general_names.get_values_for_type(type) 1228 1229 def __repr__(self): 1230 return "<SubjectAlternativeName({0})>".format(self._general_names) 1231 1232 def __eq__(self, other): 1233 if not isinstance(other, SubjectAlternativeName): 1234 return NotImplemented 1235 1236 return self._general_names == other._general_names 1237 1238 def __getitem__(self, idx): 1239 return self._general_names[idx] 1240 1241 def __ne__(self, other): 1242 return not self == other 1243 1244 def __hash__(self): 1245 return hash(self._general_names) 1246 1247 1248@utils.register_interface(ExtensionType) 1249class IssuerAlternativeName(object): 1250 oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME 1251 1252 def __init__(self, general_names): 1253 self._general_names = GeneralNames(general_names) 1254 1255 def __iter__(self): 1256 return iter(self._general_names) 1257 1258 def __len__(self): 1259 return len(self._general_names) 1260 1261 def get_values_for_type(self, type): 1262 return self._general_names.get_values_for_type(type) 1263 1264 def __repr__(self): 1265 return "<IssuerAlternativeName({0})>".format(self._general_names) 1266 1267 def __eq__(self, other): 1268 if not isinstance(other, IssuerAlternativeName): 1269 return NotImplemented 1270 1271 return self._general_names == other._general_names 1272 1273 def __ne__(self, other): 1274 return not self == other 1275 1276 def __getitem__(self, idx): 1277 return self._general_names[idx] 1278 1279 def __hash__(self): 1280 return hash(self._general_names) 1281 1282 1283@utils.register_interface(ExtensionType) 1284class CertificateIssuer(object): 1285 oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER 1286 1287 def __init__(self, general_names): 1288 self._general_names = GeneralNames(general_names) 1289 1290 def __iter__(self): 1291 return iter(self._general_names) 1292 1293 def __len__(self): 1294 return len(self._general_names) 1295 1296 def get_values_for_type(self, type): 1297 return self._general_names.get_values_for_type(type) 1298 1299 def __repr__(self): 1300 return "<CertificateIssuer({0})>".format(self._general_names) 1301 1302 def __eq__(self, other): 1303 if not isinstance(other, CertificateIssuer): 1304 return NotImplemented 1305 1306 return self._general_names == other._general_names 1307 1308 def __ne__(self, other): 1309 return not self == other 1310 1311 def __getitem__(self, idx): 1312 return self._general_names[idx] 1313 1314 def __hash__(self): 1315 return hash(self._general_names) 1316 1317 1318@utils.register_interface(ExtensionType) 1319class CRLReason(object): 1320 oid = CRLEntryExtensionOID.CRL_REASON 1321 1322 def __init__(self, reason): 1323 if not isinstance(reason, ReasonFlags): 1324 raise TypeError("reason must be an element from ReasonFlags") 1325 1326 self._reason = reason 1327 1328 def __repr__(self): 1329 return "<CRLReason(reason={0})>".format(self._reason) 1330 1331 def __eq__(self, other): 1332 if not isinstance(other, CRLReason): 1333 return NotImplemented 1334 1335 return self.reason == other.reason 1336 1337 def __ne__(self, other): 1338 return not self == other 1339 1340 def __hash__(self): 1341 return hash(self.reason) 1342 1343 reason = utils.read_only_property("_reason") 1344 1345 1346@utils.register_interface(ExtensionType) 1347class InvalidityDate(object): 1348 oid = CRLEntryExtensionOID.INVALIDITY_DATE 1349 1350 def __init__(self, invalidity_date): 1351 if not isinstance(invalidity_date, datetime.datetime): 1352 raise TypeError("invalidity_date must be a datetime.datetime") 1353 1354 self._invalidity_date = invalidity_date 1355 1356 def __repr__(self): 1357 return "<InvalidityDate(invalidity_date={0})>".format( 1358 self._invalidity_date 1359 ) 1360 1361 def __eq__(self, other): 1362 if not isinstance(other, InvalidityDate): 1363 return NotImplemented 1364 1365 return self.invalidity_date == other.invalidity_date 1366 1367 def __ne__(self, other): 1368 return not self == other 1369 1370 def __hash__(self): 1371 return hash(self.invalidity_date) 1372 1373 invalidity_date = utils.read_only_property("_invalidity_date") 1374 1375 1376@utils.register_interface(ExtensionType) 1377class PrecertificateSignedCertificateTimestamps(object): 1378 oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS 1379 1380 def __init__(self, signed_certificate_timestamps): 1381 signed_certificate_timestamps = list(signed_certificate_timestamps) 1382 if not all( 1383 isinstance(sct, SignedCertificateTimestamp) 1384 for sct in signed_certificate_timestamps 1385 ): 1386 raise TypeError( 1387 "Every item in the signed_certificate_timestamps list must be " 1388 "a SignedCertificateTimestamp" 1389 ) 1390 self._signed_certificate_timestamps = signed_certificate_timestamps 1391 1392 def __iter__(self): 1393 return iter(self._signed_certificate_timestamps) 1394 1395 def __len__(self): 1396 return len(self._signed_certificate_timestamps) 1397 1398 def __getitem__(self, idx): 1399 return self._signed_certificate_timestamps[idx] 1400 1401 def __repr__(self): 1402 return ( 1403 "<PrecertificateSignedCertificateTimestamps({0})>".format( 1404 list(self) 1405 ) 1406 ) 1407 1408 def __hash__(self): 1409 return hash(tuple(self._signed_certificate_timestamps)) 1410 1411 def __eq__(self, other): 1412 if not isinstance(other, PrecertificateSignedCertificateTimestamps): 1413 return NotImplemented 1414 1415 return ( 1416 self._signed_certificate_timestamps == 1417 other._signed_certificate_timestamps 1418 ) 1419 1420 def __ne__(self, other): 1421 return not self == other 1422 1423 1424@utils.register_interface(ExtensionType) 1425class OCSPNonce(object): 1426 oid = OCSPExtensionOID.NONCE 1427 1428 def __init__(self, nonce): 1429 if not isinstance(nonce, bytes): 1430 raise TypeError("nonce must be bytes") 1431 1432 self._nonce = nonce 1433 1434 def __eq__(self, other): 1435 if not isinstance(other, OCSPNonce): 1436 return NotImplemented 1437 1438 return self.nonce == other.nonce 1439 1440 def __ne__(self, other): 1441 return not self == other 1442 1443 def __hash__(self): 1444 return hash(self.nonce) 1445 1446 def __repr__(self): 1447 return "<OCSPNonce(nonce={0.nonce!r})>".format(self) 1448 1449 nonce = utils.read_only_property("_nonce") 1450 1451 1452@utils.register_interface(ExtensionType) 1453class IssuingDistributionPoint(object): 1454 oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT 1455 1456 def __init__(self, full_name, relative_name, only_contains_user_certs, 1457 only_contains_ca_certs, only_some_reasons, indirect_crl, 1458 only_contains_attribute_certs): 1459 if ( 1460 only_some_reasons and ( 1461 not isinstance(only_some_reasons, frozenset) or not all( 1462 isinstance(x, ReasonFlags) for x in only_some_reasons 1463 ) 1464 ) 1465 ): 1466 raise TypeError( 1467 "only_some_reasons must be None or frozenset of ReasonFlags" 1468 ) 1469 1470 if only_some_reasons and ( 1471 ReasonFlags.unspecified in only_some_reasons or 1472 ReasonFlags.remove_from_crl in only_some_reasons 1473 ): 1474 raise ValueError( 1475 "unspecified and remove_from_crl are not valid reasons in an " 1476 "IssuingDistributionPoint" 1477 ) 1478 1479 if not ( 1480 isinstance(only_contains_user_certs, bool) and 1481 isinstance(only_contains_ca_certs, bool) and 1482 isinstance(indirect_crl, bool) and 1483 isinstance(only_contains_attribute_certs, bool) 1484 ): 1485 raise TypeError( 1486 "only_contains_user_certs, only_contains_ca_certs, " 1487 "indirect_crl and only_contains_attribute_certs " 1488 "must all be boolean." 1489 ) 1490 1491 crl_constraints = [ 1492 only_contains_user_certs, only_contains_ca_certs, 1493 indirect_crl, only_contains_attribute_certs 1494 ] 1495 1496 if len([x for x in crl_constraints if x]) > 1: 1497 raise ValueError( 1498 "Only one of the following can be set to True: " 1499 "only_contains_user_certs, only_contains_ca_certs, " 1500 "indirect_crl, only_contains_attribute_certs" 1501 ) 1502 1503 if ( 1504 not any([ 1505 only_contains_user_certs, only_contains_ca_certs, 1506 indirect_crl, only_contains_attribute_certs, full_name, 1507 relative_name, only_some_reasons 1508 ]) 1509 ): 1510 raise ValueError( 1511 "Cannot create empty extension: " 1512 "if only_contains_user_certs, only_contains_ca_certs, " 1513 "indirect_crl, and only_contains_attribute_certs are all False" 1514 ", then either full_name, relative_name, or only_some_reasons " 1515 "must have a value." 1516 ) 1517 1518 self._only_contains_user_certs = only_contains_user_certs 1519 self._only_contains_ca_certs = only_contains_ca_certs 1520 self._indirect_crl = indirect_crl 1521 self._only_contains_attribute_certs = only_contains_attribute_certs 1522 self._only_some_reasons = only_some_reasons 1523 self._full_name = full_name 1524 self._relative_name = relative_name 1525 1526 def __repr__(self): 1527 return ( 1528 "<IssuingDistributionPoint(full_name={0.full_name}, " 1529 "relative_name={0.relative_name}, " 1530 "only_contains_user_certs={0.only_contains_user_certs}, " 1531 "only_contains_ca_certs={0.only_contains_ca_certs}, " 1532 "only_some_reasons={0.only_some_reasons}, " 1533 "indirect_crl={0.indirect_crl}, " 1534 "only_contains_attribute_certs=" 1535 "{0.only_contains_attribute_certs})>".format(self) 1536 ) 1537 1538 def __eq__(self, other): 1539 if not isinstance(other, IssuingDistributionPoint): 1540 return NotImplemented 1541 1542 return ( 1543 self.full_name == other.full_name and 1544 self.relative_name == other.relative_name and 1545 self.only_contains_user_certs == other.only_contains_user_certs and 1546 self.only_contains_ca_certs == other.only_contains_ca_certs and 1547 self.only_some_reasons == other.only_some_reasons and 1548 self.indirect_crl == other.indirect_crl and 1549 self.only_contains_attribute_certs == 1550 other.only_contains_attribute_certs 1551 ) 1552 1553 def __ne__(self, other): 1554 return not self == other 1555 1556 def __hash__(self): 1557 return hash(( 1558 self.full_name, 1559 self.relative_name, 1560 self.only_contains_user_certs, 1561 self.only_contains_ca_certs, 1562 self.only_some_reasons, 1563 self.indirect_crl, 1564 self.only_contains_attribute_certs, 1565 )) 1566 1567 full_name = utils.read_only_property("_full_name") 1568 relative_name = utils.read_only_property("_relative_name") 1569 only_contains_user_certs = utils.read_only_property( 1570 "_only_contains_user_certs" 1571 ) 1572 only_contains_ca_certs = utils.read_only_property( 1573 "_only_contains_ca_certs" 1574 ) 1575 only_some_reasons = utils.read_only_property("_only_some_reasons") 1576 indirect_crl = utils.read_only_property("_indirect_crl") 1577 only_contains_attribute_certs = utils.read_only_property( 1578 "_only_contains_attribute_certs" 1579 ) 1580 1581 1582@utils.register_interface(ExtensionType) 1583class UnrecognizedExtension(object): 1584 def __init__(self, oid, value): 1585 if not isinstance(oid, ObjectIdentifier): 1586 raise TypeError("oid must be an ObjectIdentifier") 1587 self._oid = oid 1588 self._value = value 1589 1590 oid = utils.read_only_property("_oid") 1591 value = utils.read_only_property("_value") 1592 1593 def __repr__(self): 1594 return ( 1595 "<UnrecognizedExtension(oid={0.oid}, value={0.value!r})>".format( 1596 self 1597 ) 1598 ) 1599 1600 def __eq__(self, other): 1601 if not isinstance(other, UnrecognizedExtension): 1602 return NotImplemented 1603 1604 return self.oid == other.oid and self.value == other.value 1605 1606 def __ne__(self, other): 1607 return not self == other 1608 1609 def __hash__(self): 1610 return hash((self.oid, self.value)) 1611