Source code for cryptography.x509.extensions

# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.

from __future__ import absolute_import, division, print_function

import abc
import datetime
import hashlib
import ipaddress
from enum import Enum

import six

from cryptography import utils
from cryptography.hazmat._der import (
    BIT_STRING,
    DERReader,
    OBJECT_IDENTIFIER,
    SEQUENCE,
)
from cryptography.hazmat.primitives import constant_time, serialization
from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
from cryptography.x509.certificate_transparency import (
    SignedCertificateTimestamp,
)
from cryptography.x509.general_name import GeneralName, IPAddress, OtherName
from cryptography.x509.name import RelativeDistinguishedName
from cryptography.x509.oid import (
    CRLEntryExtensionOID,
    ExtensionOID,
    OCSPExtensionOID,
    ObjectIdentifier,
)


def _key_identifier_from_public_key(public_key):
    if isinstance(public_key, RSAPublicKey):
        data = public_key.public_bytes(
            serialization.Encoding.DER,
            serialization.PublicFormat.PKCS1,
        )
    elif isinstance(public_key, EllipticCurvePublicKey):
        data = public_key.public_bytes(
            serialization.Encoding.X962,
            serialization.PublicFormat.UncompressedPoint,
        )
    else:
        # This is a very slow way to do this.
        serialized = public_key.public_bytes(
            serialization.Encoding.DER,
            serialization.PublicFormat.SubjectPublicKeyInfo,
        )

        reader = DERReader(serialized)
        with reader.read_single_element(SEQUENCE) as public_key_info:
            algorithm = public_key_info.read_element(SEQUENCE)
            public_key = public_key_info.read_element(BIT_STRING)

        # Double-check the algorithm structure.
        with algorithm:
            algorithm.read_element(OBJECT_IDENTIFIER)
            if not algorithm.is_empty():
                # Skip the optional parameters field.
                algorithm.read_any_element()

        # BIT STRING contents begin with the number of padding bytes added. It
        # must be zero for SubjectPublicKeyInfo structures.
        if public_key.read_byte() != 0:
            raise ValueError("Invalid public key encoding")

        data = public_key.data

    return hashlib.sha1(data).digest()


def _make_sequence_methods(field_name):
    def len_method(self):
        return len(getattr(self, field_name))

    def iter_method(self):
        return iter(getattr(self, field_name))

    def getitem_method(self, idx):
        return getattr(self, field_name)[idx]

    return len_method, iter_method, getitem_method


[docs]class DuplicateExtension(Exception): def __init__(self, msg, oid): super(DuplicateExtension, self).__init__(msg) self.oid = oid
[docs]class ExtensionNotFound(Exception): def __init__(self, msg, oid): super(ExtensionNotFound, self).__init__(msg) self.oid = oid
[docs]@six.add_metaclass(abc.ABCMeta) class ExtensionType(object): @abc.abstractproperty def oid(self): """ Returns the oid associated with the given extension type. """
[docs]class Extensions(object): def __init__(self, extensions): self._extensions = extensions
[docs] def get_extension_for_oid(self, oid): for ext in self: if ext.oid == oid: return ext raise ExtensionNotFound("No {} extension was found".format(oid), oid)
[docs] def get_extension_for_class(self, extclass): if extclass is UnrecognizedExtension: raise TypeError( "UnrecognizedExtension can't be used with " "get_extension_for_class because more than one instance of the" " class may be present." ) for ext in self: if isinstance(ext.value, extclass): return ext raise ExtensionNotFound( "No {} extension was found".format(extclass), extclass.oid )
__len__, __iter__, __getitem__ = _make_sequence_methods("_extensions") def __repr__(self): return "<Extensions({})>".format(self._extensions)
[docs]@utils.register_interface(ExtensionType) class CRLNumber(object): oid = ExtensionOID.CRL_NUMBER def __init__(self, crl_number): if not isinstance(crl_number, six.integer_types): raise TypeError("crl_number must be an integer") self._crl_number = crl_number def __eq__(self, other): if not isinstance(other, CRLNumber): return NotImplemented return self.crl_number == other.crl_number def __ne__(self, other): return not self == other def __hash__(self): return hash(self.crl_number) def __repr__(self): return "<CRLNumber({})>".format(self.crl_number) crl_number = utils.read_only_property("_crl_number")
[docs]@utils.register_interface(ExtensionType) class AuthorityKeyIdentifier(object): oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER def __init__( self, key_identifier, authority_cert_issuer, authority_cert_serial_number, ): if (authority_cert_issuer is None) != ( authority_cert_serial_number is None ): raise ValueError( "authority_cert_issuer and authority_cert_serial_number " "must both be present or both None" ) if authority_cert_issuer is not None: authority_cert_issuer = list(authority_cert_issuer) if not all( isinstance(x, GeneralName) for x in authority_cert_issuer ): raise TypeError( "authority_cert_issuer must be a list of GeneralName " "objects" ) if authority_cert_serial_number is not None and not isinstance( authority_cert_serial_number, six.integer_types ): raise TypeError("authority_cert_serial_number must be an integer") self._key_identifier = key_identifier self._authority_cert_issuer = authority_cert_issuer self._authority_cert_serial_number = authority_cert_serial_number
[docs] @classmethod def from_issuer_public_key(cls, public_key): digest = _key_identifier_from_public_key(public_key) return cls( key_identifier=digest, authority_cert_issuer=None, authority_cert_serial_number=None, )
[docs] @classmethod def from_issuer_subject_key_identifier(cls, ski): return cls( key_identifier=ski.digest, authority_cert_issuer=None, authority_cert_serial_number=None, )
def __repr__(self): return ( "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, " "authority_cert_issuer={0.authority_cert_issuer}, " "authority_cert_serial_number={0.authority_cert_serial_number}" ")>".format(self) ) def __eq__(self, other): if not isinstance(other, AuthorityKeyIdentifier): return NotImplemented return ( self.key_identifier == other.key_identifier and self.authority_cert_issuer == other.authority_cert_issuer and self.authority_cert_serial_number == other.authority_cert_serial_number ) def __ne__(self, other): return not self == other def __hash__(self): if self.authority_cert_issuer is None: aci = None else: aci = tuple(self.authority_cert_issuer) return hash( (self.key_identifier, aci, self.authority_cert_serial_number) ) key_identifier = utils.read_only_property("_key_identifier") authority_cert_issuer = utils.read_only_property("_authority_cert_issuer") authority_cert_serial_number = utils.read_only_property( "_authority_cert_serial_number" )
[docs]@utils.register_interface(ExtensionType) class SubjectKeyIdentifier(object): oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER def __init__(self, digest): self._digest = digest
[docs] @classmethod def from_public_key(cls, public_key): return cls(_key_identifier_from_public_key(public_key))
digest = utils.read_only_property("_digest") def __repr__(self): return "<SubjectKeyIdentifier(digest={0!r})>".format(self.digest) def __eq__(self, other): if not isinstance(other, SubjectKeyIdentifier): return NotImplemented return constant_time.bytes_eq(self.digest, other.digest) def __ne__(self, other): return not self == other def __hash__(self): return hash(self.digest)
[docs]@utils.register_interface(ExtensionType) class AuthorityInformationAccess(object): oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS def __init__(self, descriptions): descriptions = list(descriptions) if not all(isinstance(x, AccessDescription) for x in descriptions): raise TypeError( "Every item in the descriptions list must be an " "AccessDescription" ) self._descriptions = descriptions __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") def __repr__(self): return "<AuthorityInformationAccess({})>".format(self._descriptions) def __eq__(self, other): if not isinstance(other, AuthorityInformationAccess): return NotImplemented return self._descriptions == other._descriptions def __ne__(self, other): return not self == other def __hash__(self): return hash(tuple(self._descriptions))
[docs]@utils.register_interface(ExtensionType) class SubjectInformationAccess(object): oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS def __init__(self, descriptions): descriptions = list(descriptions) if not all(isinstance(x, AccessDescription) for x in descriptions): raise TypeError( "Every item in the descriptions list must be an " "AccessDescription" ) self._descriptions = descriptions __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions") def __repr__(self): return "<SubjectInformationAccess({})>".format(self._descriptions) def __eq__(self, other): if not isinstance(other, SubjectInformationAccess): return NotImplemented return self._descriptions == other._descriptions def __ne__(self, other): return not self == other def __hash__(self): return hash(tuple(self._descriptions))
[docs]class AccessDescription(object): def __init__(self, access_method, access_location): if not isinstance(access_method, ObjectIdentifier): raise TypeError("access_method must be an ObjectIdentifier") if not isinstance(access_location, GeneralName): raise TypeError("access_location must be a GeneralName") self._access_method = access_method self._access_location = access_location def __repr__(self): return ( "<AccessDescription(access_method={0.access_method}, access_locati" "on={0.access_location})>".format(self) ) def __eq__(self, other): if not isinstance(other, AccessDescription): return NotImplemented return ( self.access_method == other.access_method and self.access_location == other.access_location ) def __ne__(self, other): return not self == other def __hash__(self): return hash((self.access_method, self.access_location)) access_method = utils.read_only_property("_access_method") access_location = utils.read_only_property("_access_location")
[docs]@utils.register_interface(ExtensionType) class BasicConstraints(object): oid = ExtensionOID.BASIC_CONSTRAINTS def __init__(self, ca, path_length): if not isinstance(ca, bool): raise TypeError("ca must be a boolean value") if path_length is not None and not ca: raise ValueError("path_length must be None when ca is False") if path_length is not None and ( not isinstance(path_length, six.integer_types) or path_length < 0 ): raise TypeError( "path_length must be a non-negative integer or None" ) self._ca = ca self._path_length = path_length ca = utils.read_only_property("_ca") path_length = utils.read_only_property("_path_length") def __repr__(self): return ( "<BasicConstraints(ca={0.ca}, " "path_length={0.path_length})>" ).format(self) def __eq__(self, other): if not isinstance(other, BasicConstraints): return NotImplemented return self.ca == other.ca and self.path_length == other.path_length def __ne__(self, other): return not self == other def __hash__(self): return hash((self.ca, self.path_length))
[docs]@utils.register_interface(ExtensionType) class DeltaCRLIndicator(object): oid = ExtensionOID.DELTA_CRL_INDICATOR def __init__(self, crl_number): if not isinstance(crl_number, six.integer_types): raise TypeError("crl_number must be an integer") self._crl_number = crl_number crl_number = utils.read_only_property("_crl_number") def __eq__(self, other): if not isinstance(other, DeltaCRLIndicator): return NotImplemented return self.crl_number == other.crl_number def __ne__(self, other): return not self == other def __hash__(self): return hash(self.crl_number) def __repr__(self): return "<DeltaCRLIndicator(crl_number={0.crl_number})>".format(self)
[docs]@utils.register_interface(ExtensionType) class CRLDistributionPoints(object): oid = ExtensionOID.CRL_DISTRIBUTION_POINTS def __init__(self, distribution_points): distribution_points = list(distribution_points) if not all( isinstance(x, DistributionPoint) for x in distribution_points ): raise TypeError( "distribution_points must be a list of DistributionPoint " "objects" ) self._distribution_points = distribution_points __len__, __iter__, __getitem__ = _make_sequence_methods( "_distribution_points" ) def __repr__(self): return "<CRLDistributionPoints({})>".format(self._distribution_points) def __eq__(self, other): if not isinstance(other, CRLDistributionPoints): return NotImplemented return self._distribution_points == other._distribution_points def __ne__(self, other): return not self == other def __hash__(self): return hash(tuple(self._distribution_points))
[docs]@utils.register_interface(ExtensionType) class FreshestCRL(object): oid = ExtensionOID.FRESHEST_CRL def __init__(self, distribution_points): distribution_points = list(distribution_points) if not all( isinstance(x, DistributionPoint) for x in distribution_points ): raise TypeError( "distribution_points must be a list of DistributionPoint " "objects" ) self._distribution_points = distribution_points __len__, __iter__, __getitem__ = _make_sequence_methods( "_distribution_points" ) def __repr__(self): return "<FreshestCRL({})>".format(self._distribution_points) def __eq__(self, other): if not isinstance(other, FreshestCRL): return NotImplemented return self._distribution_points == other._distribution_points def __ne__(self, other): return not self == other def __hash__(self): return hash(tuple(self._distribution_points))
[docs]class DistributionPoint(object): def __init__(self, full_name, relative_name, reasons, crl_issuer): if full_name and relative_name: raise ValueError( "You cannot provide both full_name and relative_name, at " "least one must be None." ) if full_name: full_name = list(full_name) if not all(isinstance(x, GeneralName) for x in full_name): raise TypeError( "full_name must be a list of GeneralName objects" ) if relative_name: if not isinstance(relative_name, RelativeDistinguishedName): raise TypeError( "relative_name must be a RelativeDistinguishedName" ) if crl_issuer: crl_issuer = list(crl_issuer) if not all(isinstance(x, GeneralName) for x in crl_issuer): raise TypeError( "crl_issuer must be None or a list of general names" ) if reasons and ( not isinstance(reasons, frozenset) or not all(isinstance(x, ReasonFlags) for x in reasons) ): raise TypeError("reasons must be None or frozenset of ReasonFlags") if reasons and ( ReasonFlags.unspecified in reasons or ReasonFlags.remove_from_crl in reasons ): raise ValueError( "unspecified and remove_from_crl are not valid reasons in a " "DistributionPoint" ) if reasons and not crl_issuer and not (full_name or relative_name): raise ValueError( "You must supply crl_issuer, full_name, or relative_name when " "reasons is not None" ) self._full_name = full_name self._relative_name = relative_name self._reasons = reasons self._crl_issuer = crl_issuer def __repr__(self): return ( "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela" "tive_name}, reasons={0.reasons}, " "crl_issuer={0.crl_issuer})>".format(self) ) def __eq__(self, other): if not isinstance(other, DistributionPoint): return NotImplemented return ( self.full_name == other.full_name and self.relative_name == other.relative_name and self.reasons == other.reasons and self.crl_issuer == other.crl_issuer ) def __ne__(self, other): return not self == other def __hash__(self): if self.full_name is not None: fn = tuple(self.full_name) else: fn = None if self.crl_issuer is not None: crl_issuer = tuple(self.crl_issuer) else: crl_issuer = None return hash((fn, self.relative_name, self.reasons, crl_issuer)) full_name = utils.read_only_property("_full_name") relative_name = utils.read_only_property("_relative_name") reasons = utils.read_only_property("_reasons") crl_issuer = utils.read_only_property("_crl_issuer")
[docs]class ReasonFlags(Enum): unspecified = "unspecified" key_compromise = "keyCompromise" ca_compromise = "cACompromise" affiliation_changed = "affiliationChanged" superseded = "superseded" cessation_of_operation = "cessationOfOperation" certificate_hold = "certificateHold" privilege_withdrawn = "privilegeWithdrawn" aa_compromise = "aACompromise" remove_from_crl = "removeFromCRL"
[docs]@utils.register_interface(ExtensionType) class PolicyConstraints(object): oid = ExtensionOID.POLICY_CONSTRAINTS def __init__(self, require_explicit_policy, inhibit_policy_mapping): if require_explicit_policy is not None and not isinstance( require_explicit_policy, six.integer_types ): raise TypeError( "require_explicit_policy must be a non-negative integer or " "None" ) if inhibit_policy_mapping is not None and not isinstance( inhibit_policy_mapping, six.integer_types ): raise TypeError( "inhibit_policy_mapping must be a non-negative integer or None" ) if inhibit_policy_mapping is None and require_explicit_policy is None: raise ValueError( "At least one of require_explicit_policy and " "inhibit_policy_mapping must not be None" ) self._require_explicit_policy = require_explicit_policy self._inhibit_policy_mapping = inhibit_policy_mapping def __repr__(self): return ( u"<PolicyConstraints(require_explicit_policy={0.require_explicit" u"_policy}, inhibit_policy_mapping={0.inhibit_policy_" u"mapping})>".format(self) ) def __eq__(self, other): if not isinstance(other, PolicyConstraints): return NotImplemented return ( self.require_explicit_policy == other.require_explicit_policy and self.inhibit_policy_mapping == other.inhibit_policy_mapping ) def __ne__(self, other): return not self == other def __hash__(self): return hash( (self.require_explicit_policy, self.inhibit_policy_mapping) ) require_explicit_policy = utils.read_only_property( "_require_explicit_policy" ) inhibit_policy_mapping = utils.read_only_property( "_inhibit_policy_mapping" )
[docs]@utils.register_interface(ExtensionType) class CertificatePolicies(object): oid = ExtensionOID.CERTIFICATE_POLICIES def __init__(self, policies): policies = list(policies) if not all(isinstance(x, PolicyInformation) for x in policies): raise TypeError( "Every item in the policies list must be a " "PolicyInformation" ) self._policies = policies __len__, __iter__, __getitem__ = _make_sequence_methods("_policies") def __repr__(self): return "<CertificatePolicies({})>".format(self._policies) def __eq__(self, other): if not isinstance(other, CertificatePolicies): return NotImplemented return self._policies == other._policies def __ne__(self, other): return not self == other def __hash__(self): return hash(tuple(self._policies))
[docs]class PolicyInformation(object): def __init__(self, policy_identifier, policy_qualifiers): if not isinstance(policy_identifier, ObjectIdentifier): raise TypeError("policy_identifier must be an ObjectIdentifier") self._policy_identifier = policy_identifier if policy_qualifiers: policy_qualifiers = list(policy_qualifiers) if not all( isinstance(x, (six.text_type, UserNotice)) for x in policy_qualifiers ): raise TypeError( "policy_qualifiers must be a list of strings and/or " "UserNotice objects or None" ) self._policy_qualifiers = policy_qualifiers def __repr__(self): return ( "<PolicyInformation(policy_identifier={0.policy_identifier}, polic" "y_qualifiers={0.policy_qualifiers})>".format(self) ) def __eq__(self, other): if not isinstance(other, PolicyInformation): return NotImplemented return ( self.policy_identifier == other.policy_identifier and self.policy_qualifiers == other.policy_qualifiers ) def __ne__(self, other): return not self == other def __hash__(self): if self.policy_qualifiers is not None: pq = tuple(self.policy_qualifiers) else: pq = None return hash((self.policy_identifier, pq)) policy_identifier = utils.read_only_property("_policy_identifier") policy_qualifiers = utils.read_only_property("_policy_qualifiers")
[docs]class UserNotice(object): def __init__(self, notice_reference, explicit_text): if notice_reference and not isinstance( notice_reference, NoticeReference ): raise TypeError( "notice_reference must be None or a NoticeReference" ) self._notice_reference = notice_reference self._explicit_text = explicit_text def __repr__(self): return ( "<UserNotice(notice_reference={0.notice_reference}, explicit_text=" "{0.explicit_text!r})>".format(self) ) def __eq__(self, other): if not isinstance(other, UserNotice): return NotImplemented return ( self.notice_reference == other.notice_reference and self.explicit_text == other.explicit_text ) def __ne__(self, other): return not self == other def __hash__(self): return hash((self.notice_reference, self.explicit_text)) notice_reference = utils.read_only_property("_notice_reference") explicit_text = utils.read_only_property("_explicit_text")
[docs]class NoticeReference(object): def __init__(self, organization, notice_numbers): self._organization = organization notice_numbers = list(notice_numbers) if not all(isinstance(x, int) for x in notice_numbers): raise TypeError("notice_numbers must be a list of integers") self._notice_numbers = notice_numbers def __repr__(self): return ( "<NoticeReference(organization={0.organization!r}, notice_numbers=" "{0.notice_numbers})>".format(self) ) def __eq__(self, other): if not isinstance(other, NoticeReference): return NotImplemented return ( self.organization == other.organization and self.notice_numbers == other.notice_numbers ) def __ne__(self, other): return not self == other def __hash__(self): return hash((self.organization, tuple(self.notice_numbers))) organization = utils.read_only_property("_organization") notice_numbers = utils.read_only_property("_notice_numbers")
[docs]@utils.register_interface(ExtensionType) class ExtendedKeyUsage(object): oid = ExtensionOID.EXTENDED_KEY_USAGE def __init__(self, usages): usages = list(usages) if not all(isinstance(x, ObjectIdentifier) for x in usages): raise TypeError( "Every item in the usages list must be an ObjectIdentifier" ) self._usages = usages __len__, __iter__, __getitem__ = _make_sequence_methods("_usages") def __repr__(self): return "<ExtendedKeyUsage({})>".format(self._usages) def __eq__(self, other): if not isinstance(other, ExtendedKeyUsage): return NotImplemented return self._usages == other._usages def __ne__(self, other): return not self == other def __hash__(self): return hash(tuple(self._usages))
[docs]@utils.register_interface(ExtensionType) class OCSPNoCheck(object): oid = ExtensionOID.OCSP_NO_CHECK def __eq__(self, other): if not isinstance(other, OCSPNoCheck): return NotImplemented return True def __ne__(self, other): return not self == other def __hash__(self): return hash(OCSPNoCheck) def __repr__(self): return "<OCSPNoCheck()>"
[docs]@utils.register_interface(ExtensionType) class PrecertPoison(object): oid = ExtensionOID.PRECERT_POISON def __eq__(self, other): if not isinstance(other, PrecertPoison): return NotImplemented return True def __ne__(self, other): return not self == other def __hash__(self): return hash(PrecertPoison) def __repr__(self): return "<PrecertPoison()>"
[docs]@utils.register_interface(ExtensionType) class TLSFeature(object): oid = ExtensionOID.TLS_FEATURE def __init__(self, features): features = list(features) if ( not all(isinstance(x, TLSFeatureType) for x in features) or len(features) == 0 ): raise TypeError( "features must be a list of elements from the TLSFeatureType " "enum" ) self._features = features __len__, __iter__, __getitem__ = _make_sequence_methods("_features") def __repr__(self): return "<TLSFeature(features={0._features})>".format(self) def __eq__(self, other): if not isinstance(other, TLSFeature): return NotImplemented return self._features == other._features def __ne__(self, other): return not self == other def __hash__(self): return hash(tuple(self._features))
[docs]class TLSFeatureType(Enum): # status_request is defined in RFC 6066 and is used for what is commonly # called OCSP Must-Staple when present in the TLS Feature extension in an # X.509 certificate. status_request = 5 # status_request_v2 is defined in RFC 6961 and allows multiple OCSP # responses to be provided. It is not currently in use by clients or # servers. status_request_v2 = 17
_TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType}
[docs]@utils.register_interface(ExtensionType) class InhibitAnyPolicy(object): oid = ExtensionOID.INHIBIT_ANY_POLICY def __init__(self, skip_certs): if not isinstance(skip_certs, six.integer_types): raise TypeError("skip_certs must be an integer") if skip_certs < 0: raise ValueError("skip_certs must be a non-negative integer") self._skip_certs = skip_certs def __repr__(self): return "<InhibitAnyPolicy(skip_certs={0.skip_certs})>".format(self) def __eq__(self, other): if not isinstance(other, InhibitAnyPolicy): return NotImplemented return self.skip_certs == other.skip_certs def __ne__(self, other): return not self == other def __hash__(self): return hash(self.skip_certs) skip_certs = utils.read_only_property("_skip_certs")
[docs]@utils.register_interface(ExtensionType) class KeyUsage(object): oid = ExtensionOID.KEY_USAGE def __init__( self, digital_signature, content_commitment, key_encipherment, data_encipherment, key_agreement, key_cert_sign, crl_sign, encipher_only, decipher_only, ): if not key_agreement and (encipher_only or decipher_only): raise ValueError( "encipher_only and decipher_only can only be true when " "key_agreement is true" ) self._digital_signature = digital_signature self._content_commitment = content_commitment self._key_encipherment = key_encipherment self._data_encipherment = data_encipherment self._key_agreement = key_agreement self._key_cert_sign = key_cert_sign self._crl_sign = crl_sign self._encipher_only = encipher_only self._decipher_only = decipher_only digital_signature = utils.read_only_property("_digital_signature") content_commitment = utils.read_only_property("_content_commitment") key_encipherment = utils.read_only_property("_key_encipherment") data_encipherment = utils.read_only_property("_data_encipherment") key_agreement = utils.read_only_property("_key_agreement") key_cert_sign = utils.read_only_property("_key_cert_sign") crl_sign = utils.read_only_property("_crl_sign") @property def encipher_only(self): if not self.key_agreement: raise ValueError( "encipher_only is undefined unless key_agreement is true" ) else: return self._encipher_only @property def decipher_only(self): if not self.key_agreement: raise ValueError( "decipher_only is undefined unless key_agreement is true" ) else: return self._decipher_only def __repr__(self): try: encipher_only = self.encipher_only decipher_only = self.decipher_only except ValueError: # Users found None confusing because even though encipher/decipher # have no meaning unless key_agreement is true, to construct an # instance of the class you still need to pass False. encipher_only = False decipher_only = False return ( "<KeyUsage(digital_signature={0.digital_signature}, " "content_commitment={0.content_commitment}, " "key_encipherment={0.key_encipherment}, " "data_encipherment={0.data_encipherment}, " "key_agreement={0.key_agreement}, " "key_cert_sign={0.key_cert_sign}, crl_sign={0.crl_sign}, " "encipher_only={1}, decipher_only={2})>" ).format(self, encipher_only, decipher_only) def __eq__(self, other): if not isinstance(other, KeyUsage): return NotImplemented return ( self.digital_signature == other.digital_signature and self.content_commitment == other.content_commitment and self.key_encipherment == other.key_encipherment and self.data_encipherment == other.data_encipherment and self.key_agreement == other.key_agreement and self.key_cert_sign == other.key_cert_sign and self.crl_sign == other.crl_sign and self._encipher_only == other._encipher_only and self._decipher_only == other._decipher_only ) def __ne__(self, other): return not self == other def __hash__(self): return hash( ( self.digital_signature, self.content_commitment, self.key_encipherment, self.data_encipherment, self.key_agreement, self.key_cert_sign, self.crl_sign, self._encipher_only, self._decipher_only, ) )
[docs]@utils.register_interface(ExtensionType) class NameConstraints(object): oid = ExtensionOID.NAME_CONSTRAINTS def __init__(self, permitted_subtrees, excluded_subtrees): if permitted_subtrees is not None: permitted_subtrees = list(permitted_subtrees) if not all(isinstance(x, GeneralName) for x in permitted_subtrees): raise TypeError( "permitted_subtrees must be a list of GeneralName objects " "or None" ) self._validate_ip_name(permitted_subtrees) if excluded_subtrees is not None: excluded_subtrees = list(excluded_subtrees) if not all(isinstance(x, GeneralName) for x in excluded_subtrees): raise TypeError( "excluded_subtrees must be a list of GeneralName objects " "or None" ) self._validate_ip_name(excluded_subtrees) if permitted_subtrees is None and excluded_subtrees is None: raise ValueError( "At least one of permitted_subtrees and excluded_subtrees " "must not be None" ) self._permitted_subtrees = permitted_subtrees self._excluded_subtrees = excluded_subtrees def __eq__(self, other): if not isinstance(other, NameConstraints): return NotImplemented return ( self.excluded_subtrees == other.excluded_subtrees and self.permitted_subtrees == other.permitted_subtrees ) def __ne__(self, other): return not self == other def _validate_ip_name(self, tree): if any( isinstance(name, IPAddress) and not isinstance( name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network) ) for name in tree ): raise TypeError( "IPAddress name constraints must be an IPv4Network or" " IPv6Network object" ) def __repr__(self): return ( u"<NameConstraints(permitted_subtrees={0.permitted_subtrees}, " u"excluded_subtrees={0.excluded_subtrees})>".format(self) ) def __hash__(self): if self.permitted_subtrees is not None: ps = tuple(self.permitted_subtrees) else: ps = None if self.excluded_subtrees is not None: es = tuple(self.excluded_subtrees) else: es = None return hash((ps, es)) permitted_subtrees = utils.read_only_property("_permitted_subtrees") excluded_subtrees = utils.read_only_property("_excluded_subtrees")
[docs]class Extension(object): def __init__(self, oid, critical, value): if not isinstance(oid, ObjectIdentifier): raise TypeError( "oid argument must be an ObjectIdentifier instance." ) if not isinstance(critical, bool): raise TypeError("critical must be a boolean value") self._oid = oid self._critical = critical self._value = value oid = utils.read_only_property("_oid") critical = utils.read_only_property("_critical") value = utils.read_only_property("_value") def __repr__(self): return ( "<Extension(oid={0.oid}, critical={0.critical}, " "value={0.value})>" ).format(self) def __eq__(self, other): if not isinstance(other, Extension): return NotImplemented return ( self.oid == other.oid and self.critical == other.critical and self.value == other.value ) def __ne__(self, other): return not self == other def __hash__(self): return hash((self.oid, self.critical, self.value))
class GeneralNames(object): def __init__(self, general_names): general_names = list(general_names) if not all(isinstance(x, GeneralName) for x in general_names): raise TypeError( "Every item in the general_names list must be an " "object conforming to the GeneralName interface" ) self._general_names = general_names __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names") def get_values_for_type(self, type): # Return the value of each GeneralName, except for OtherName instances # which we return directly because it has two important properties not # just one value. objs = (i for i in self if isinstance(i, type)) if type != OtherName: objs = (i.value for i in objs) return list(objs) def __repr__(self): return "<GeneralNames({})>".format(self._general_names) def __eq__(self, other): if not isinstance(other, GeneralNames): return NotImplemented return self._general_names == other._general_names def __ne__(self, other): return not self == other def __hash__(self): return hash(tuple(self._general_names))
[docs]@utils.register_interface(ExtensionType) class SubjectAlternativeName(object): oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME def __init__(self, general_names): self._general_names = GeneralNames(general_names) __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
[docs] def get_values_for_type(self, type): return self._general_names.get_values_for_type(type)
def __repr__(self): return "<SubjectAlternativeName({})>".format(self._general_names) def __eq__(self, other): if not isinstance(other, SubjectAlternativeName): return NotImplemented return self._general_names == other._general_names def __ne__(self, other): return not self == other def __hash__(self): return hash(self._general_names)
[docs]@utils.register_interface(ExtensionType) class IssuerAlternativeName(object): oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME def __init__(self, general_names): self._general_names = GeneralNames(general_names) __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
[docs] def get_values_for_type(self, type): return self._general_names.get_values_for_type(type)
def __repr__(self): return "<IssuerAlternativeName({})>".format(self._general_names) def __eq__(self, other): if not isinstance(other, IssuerAlternativeName): return NotImplemented return self._general_names == other._general_names def __ne__(self, other): return not self == other def __hash__(self): return hash(self._general_names)
[docs]@utils.register_interface(ExtensionType) class CertificateIssuer(object): oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER def __init__(self, general_names): self._general_names = GeneralNames(general_names) __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
[docs] def get_values_for_type(self, type): return self._general_names.get_values_for_type(type)
def __repr__(self): return "<CertificateIssuer({})>".format(self._general_names) def __eq__(self, other): if not isinstance(other, CertificateIssuer): return NotImplemented return self._general_names == other._general_names def __ne__(self, other): return not self == other def __hash__(self): return hash(self._general_names)
[docs]@utils.register_interface(ExtensionType) class CRLReason(object): oid = CRLEntryExtensionOID.CRL_REASON def __init__(self, reason): if not isinstance(reason, ReasonFlags): raise TypeError("reason must be an element from ReasonFlags") self._reason = reason def __repr__(self): return "<CRLReason(reason={})>".format(self._reason) def __eq__(self, other): if not isinstance(other, CRLReason): return NotImplemented return self.reason == other.reason def __ne__(self, other): return not self == other def __hash__(self): return hash(self.reason) reason = utils.read_only_property("_reason")
[docs]@utils.register_interface(ExtensionType) class InvalidityDate(object): oid = CRLEntryExtensionOID.INVALIDITY_DATE def __init__(self, invalidity_date): if not isinstance(invalidity_date, datetime.datetime): raise TypeError("invalidity_date must be a datetime.datetime") self._invalidity_date = invalidity_date def __repr__(self): return "<InvalidityDate(invalidity_date={})>".format( self._invalidity_date ) def __eq__(self, other): if not isinstance(other, InvalidityDate): return NotImplemented return self.invalidity_date == other.invalidity_date def __ne__(self, other): return not self == other def __hash__(self): return hash(self.invalidity_date) invalidity_date = utils.read_only_property("_invalidity_date")
[docs]@utils.register_interface(ExtensionType) class PrecertificateSignedCertificateTimestamps(object): oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS def __init__(self, signed_certificate_timestamps): signed_certificate_timestamps = list(signed_certificate_timestamps) if not all( isinstance(sct, SignedCertificateTimestamp) for sct in signed_certificate_timestamps ): raise TypeError( "Every item in the signed_certificate_timestamps list must be " "a SignedCertificateTimestamp" ) self._signed_certificate_timestamps = signed_certificate_timestamps __len__, __iter__, __getitem__ = _make_sequence_methods( "_signed_certificate_timestamps" ) def __repr__(self): return "<PrecertificateSignedCertificateTimestamps({})>".format( list(self) ) def __hash__(self): return hash(tuple(self._signed_certificate_timestamps)) def __eq__(self, other): if not isinstance(other, PrecertificateSignedCertificateTimestamps): return NotImplemented return ( self._signed_certificate_timestamps == other._signed_certificate_timestamps ) def __ne__(self, other): return not self == other
[docs]@utils.register_interface(ExtensionType) class SignedCertificateTimestamps(object): oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS def __init__(self, signed_certificate_timestamps): signed_certificate_timestamps = list(signed_certificate_timestamps) if not all( isinstance(sct, SignedCertificateTimestamp) for sct in signed_certificate_timestamps ): raise TypeError( "Every item in the signed_certificate_timestamps list must be " "a SignedCertificateTimestamp" ) self._signed_certificate_timestamps = signed_certificate_timestamps __len__, __iter__, __getitem__ = _make_sequence_methods( "_signed_certificate_timestamps" ) def __repr__(self): return "<SignedCertificateTimestamps({})>".format(list(self)) def __hash__(self): return hash(tuple(self._signed_certificate_timestamps)) def __eq__(self, other): if not isinstance(other, SignedCertificateTimestamps): return NotImplemented return ( self._signed_certificate_timestamps == other._signed_certificate_timestamps ) def __ne__(self, other): return not self == other
[docs]@utils.register_interface(ExtensionType) class OCSPNonce(object): oid = OCSPExtensionOID.NONCE def __init__(self, nonce): if not isinstance(nonce, bytes): raise TypeError("nonce must be bytes") self._nonce = nonce def __eq__(self, other): if not isinstance(other, OCSPNonce): return NotImplemented return self.nonce == other.nonce def __ne__(self, other): return not self == other def __hash__(self): return hash(self.nonce) def __repr__(self): return "<OCSPNonce(nonce={0.nonce!r})>".format(self) nonce = utils.read_only_property("_nonce")
[docs]@utils.register_interface(ExtensionType) class IssuingDistributionPoint(object): oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT def __init__( self, full_name, relative_name, only_contains_user_certs, only_contains_ca_certs, only_some_reasons, indirect_crl, only_contains_attribute_certs, ): if only_some_reasons and ( not isinstance(only_some_reasons, frozenset) or not all(isinstance(x, ReasonFlags) for x in only_some_reasons) ): raise TypeError( "only_some_reasons must be None or frozenset of ReasonFlags" ) if only_some_reasons and ( ReasonFlags.unspecified in only_some_reasons or ReasonFlags.remove_from_crl in only_some_reasons ): raise ValueError( "unspecified and remove_from_crl are not valid reasons in an " "IssuingDistributionPoint" ) if not ( isinstance(only_contains_user_certs, bool) and isinstance(only_contains_ca_certs, bool) and isinstance(indirect_crl, bool) and isinstance(only_contains_attribute_certs, bool) ): raise TypeError( "only_contains_user_certs, only_contains_ca_certs, " "indirect_crl and only_contains_attribute_certs " "must all be boolean." ) crl_constraints = [ only_contains_user_certs, only_contains_ca_certs, indirect_crl, only_contains_attribute_certs, ] if len([x for x in crl_constraints if x]) > 1: raise ValueError( "Only one of the following can be set to True: " "only_contains_user_certs, only_contains_ca_certs, " "indirect_crl, only_contains_attribute_certs" ) if not any( [ only_contains_user_certs, only_contains_ca_certs, indirect_crl, only_contains_attribute_certs, full_name, relative_name, only_some_reasons, ] ): raise ValueError( "Cannot create empty extension: " "if only_contains_user_certs, only_contains_ca_certs, " "indirect_crl, and only_contains_attribute_certs are all False" ", then either full_name, relative_name, or only_some_reasons " "must have a value." ) self._only_contains_user_certs = only_contains_user_certs self._only_contains_ca_certs = only_contains_ca_certs self._indirect_crl = indirect_crl self._only_contains_attribute_certs = only_contains_attribute_certs self._only_some_reasons = only_some_reasons self._full_name = full_name self._relative_name = relative_name def __repr__(self): return ( "<IssuingDistributionPoint(full_name={0.full_name}, " "relative_name={0.relative_name}, " "only_contains_user_certs={0.only_contains_user_certs}, " "only_contains_ca_certs={0.only_contains_ca_certs}, " "only_some_reasons={0.only_some_reasons}, " "indirect_crl={0.indirect_crl}, " "only_contains_attribute_certs=" "{0.only_contains_attribute_certs})>".format(self) ) def __eq__(self, other): if not isinstance(other, IssuingDistributionPoint): return NotImplemented return ( self.full_name == other.full_name and self.relative_name == other.relative_name and self.only_contains_user_certs == other.only_contains_user_certs and self.only_contains_ca_certs == other.only_contains_ca_certs and self.only_some_reasons == other.only_some_reasons and self.indirect_crl == other.indirect_crl and self.only_contains_attribute_certs == other.only_contains_attribute_certs ) def __ne__(self, other): return not self == other def __hash__(self): return hash( ( self.full_name, self.relative_name, self.only_contains_user_certs, self.only_contains_ca_certs, self.only_some_reasons, self.indirect_crl, self.only_contains_attribute_certs, ) ) full_name = utils.read_only_property("_full_name") relative_name = utils.read_only_property("_relative_name") only_contains_user_certs = utils.read_only_property( "_only_contains_user_certs" ) only_contains_ca_certs = utils.read_only_property( "_only_contains_ca_certs" ) only_some_reasons = utils.read_only_property("_only_some_reasons") indirect_crl = utils.read_only_property("_indirect_crl") only_contains_attribute_certs = utils.read_only_property( "_only_contains_attribute_certs" )
[docs]@utils.register_interface(ExtensionType) class UnrecognizedExtension(object): def __init__(self, oid, value): if not isinstance(oid, ObjectIdentifier): raise TypeError("oid must be an ObjectIdentifier") self._oid = oid self._value = value oid = utils.read_only_property("_oid") value = utils.read_only_property("_value") def __repr__(self): return ( "<UnrecognizedExtension(oid={0.oid}, " "value={0.value!r})>".format(self) ) def __eq__(self, other): if not isinstance(other, UnrecognizedExtension): return NotImplemented return self.oid == other.oid and self.value == other.value def __ne__(self, other): return not self == other def __hash__(self): return hash((self.oid, self.value))