Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
crypto.py2146 linesDownload Raw Back to OpenSSL
1from __future__ import annotations2 3import calendar4import datetime5import functools6import sys7import typing8from base64 import b16encode9from collections.abc import Sequence10from functools import partial11from typing import (12    Any,13    Callable,14    Union,15)16 17if sys.version_info >= (3, 13):18    from warnings import deprecated19elif sys.version_info < (3, 8):20    _T = typing.TypeVar("T")21 22    def deprecated(msg: str, **kwargs: object) -> Callable[[_T], _T]:23        return lambda f: f24else:25    from typing_extensions import deprecated26 27from cryptography import utils, x50928from cryptography.hazmat.primitives.asymmetric import (29    dsa,30    ec,31    ed448,32    ed25519,33    rsa,34)35 36from OpenSSL._util import StrOrBytesPath37from OpenSSL._util import (38    byte_string as _byte_string,39)40from OpenSSL._util import (41    exception_from_error_queue as _exception_from_error_queue,42)43from OpenSSL._util import (44    ffi as _ffi,45)46from OpenSSL._util import (47    lib as _lib,48)49from OpenSSL._util import (50    make_assert as _make_assert,51)52from OpenSSL._util import (53    path_bytes as _path_bytes,54)55 56__all__ = [57    "FILETYPE_ASN1",58    "FILETYPE_PEM",59    "FILETYPE_TEXT",60    "TYPE_DSA",61    "TYPE_RSA",62    "X509",63    "Error",64    "PKey",65    "X509Name",66    "X509Req",67    "X509Store",68    "X509StoreContext",69    "X509StoreContextError",70    "X509StoreFlags",71    "dump_certificate",72    "dump_certificate_request",73    "dump_privatekey",74    "dump_publickey",75    "get_elliptic_curve",76    "get_elliptic_curves",77    "load_certificate",78    "load_certificate_request",79    "load_privatekey",80    "load_publickey",81]82 83 84_PrivateKey = Union[85    dsa.DSAPrivateKey,86    ec.EllipticCurvePrivateKey,87    ed25519.Ed25519PrivateKey,88    ed448.Ed448PrivateKey,89    rsa.RSAPrivateKey,90]91_PublicKey = Union[92    dsa.DSAPublicKey,93    ec.EllipticCurvePublicKey,94    ed25519.Ed25519PublicKey,95    ed448.Ed448PublicKey,96    rsa.RSAPublicKey,97]98_Key = Union[_PrivateKey, _PublicKey]99PassphraseCallableT = Union[bytes, Callable[..., bytes]]100 101 102FILETYPE_PEM: int = _lib.SSL_FILETYPE_PEM103FILETYPE_ASN1: int = _lib.SSL_FILETYPE_ASN1104 105# TODO This was an API mistake.  OpenSSL has no such constant.106FILETYPE_TEXT = 2**16 - 1107 108TYPE_RSA: int = _lib.EVP_PKEY_RSA109TYPE_DSA: int = _lib.EVP_PKEY_DSA110TYPE_DH: int = _lib.EVP_PKEY_DH111TYPE_EC: int = _lib.EVP_PKEY_EC112 113 114class Error(Exception):115    """116    An error occurred in an `OpenSSL.crypto` API.117    """118 119 120_raise_current_error = partial(_exception_from_error_queue, Error)121_openssl_assert = _make_assert(Error)122 123 124def _new_mem_buf(buffer: bytes | None = None) -> Any:125    """126    Allocate a new OpenSSL memory BIO.127 128    Arrange for the garbage collector to clean it up automatically.129 130    :param buffer: None or some bytes to use to put into the BIO so that they131        can be read out.132    """133    if buffer is None:134        bio = _lib.BIO_new(_lib.BIO_s_mem())135        free = _lib.BIO_free136    else:137        data = _ffi.new("char[]", buffer)138        bio = _lib.BIO_new_mem_buf(data, len(buffer))139 140        # Keep the memory alive as long as the bio is alive!141        def free(bio: Any, ref: Any = data) -> Any:142            return _lib.BIO_free(bio)143 144    _openssl_assert(bio != _ffi.NULL)145 146    bio = _ffi.gc(bio, free)147    return bio148 149 150def _bio_to_string(bio: Any) -> bytes:151    """152    Copy the contents of an OpenSSL BIO object into a Python byte string.153    """154    result_buffer = _ffi.new("char**")155    buffer_length = _lib.BIO_get_mem_data(bio, result_buffer)156    return _ffi.buffer(result_buffer[0], buffer_length)[:]157 158 159def _set_asn1_time(boundary: Any, when: bytes) -> None:160    """161    The the time value of an ASN1 time object.162 163    @param boundary: An ASN1_TIME pointer (or an object safely164        castable to that type) which will have its value set.165    @param when: A string representation of the desired time value.166 167    @raise TypeError: If C{when} is not a L{bytes} string.168    @raise ValueError: If C{when} does not represent a time in the required169        format.170    @raise RuntimeError: If the time value cannot be set for some other171        (unspecified) reason.172    """173    if not isinstance(when, bytes):174        raise TypeError("when must be a byte string")175    # ASN1_TIME_set_string validates the string without writing anything176    # when the destination is NULL.177    _openssl_assert(boundary != _ffi.NULL)178 179    set_result = _lib.ASN1_TIME_set_string(boundary, when)180    if set_result == 0:181        raise ValueError("Invalid string")182 183 184def _new_asn1_time(when: bytes) -> Any:185    """186    Behaves like _set_asn1_time but returns a new ASN1_TIME object.187 188    @param when: A string representation of the desired time value.189 190    @raise TypeError: If C{when} is not a L{bytes} string.191    @raise ValueError: If C{when} does not represent a time in the required192        format.193    @raise RuntimeError: If the time value cannot be set for some other194        (unspecified) reason.195    """196    ret = _lib.ASN1_TIME_new()197    _openssl_assert(ret != _ffi.NULL)198    ret = _ffi.gc(ret, _lib.ASN1_TIME_free)199    _set_asn1_time(ret, when)200    return ret201 202 203def _get_asn1_time(timestamp: Any) -> bytes | None:204    """205    Retrieve the time value of an ASN1 time object.206 207    @param timestamp: An ASN1_GENERALIZEDTIME* (or an object safely castable to208        that type) from which the time value will be retrieved.209 210    @return: The time value from C{timestamp} as a L{bytes} string in a certain211        format.  Or C{None} if the object contains no time value.212    """213    string_timestamp = _ffi.cast("ASN1_STRING*", timestamp)214    if _lib.ASN1_STRING_length(string_timestamp) == 0:215        return None216    elif (217        _lib.ASN1_STRING_type(string_timestamp) == _lib.V_ASN1_GENERALIZEDTIME218    ):219        return _ffi.string(_lib.ASN1_STRING_get0_data(string_timestamp))220    else:221        generalized_timestamp = _ffi.new("ASN1_GENERALIZEDTIME**")222        _lib.ASN1_TIME_to_generalizedtime(timestamp, generalized_timestamp)223        _openssl_assert(generalized_timestamp[0] != _ffi.NULL)224 225        string_timestamp = _ffi.cast("ASN1_STRING*", generalized_timestamp[0])226        string_data = _lib.ASN1_STRING_get0_data(string_timestamp)227        string_result = _ffi.string(string_data)228        _lib.ASN1_GENERALIZEDTIME_free(generalized_timestamp[0])229        return string_result230 231 232class _X509NameInvalidator:233    def __init__(self) -> None:234        self._names: list[X509Name] = []235 236    def add(self, name: X509Name) -> None:237        self._names.append(name)238 239    def clear(self) -> None:240        for name in self._names:241            # Breaks the object, but also prevents UAF!242            del name._name243 244 245class PKey:246    """247    A class representing an DSA or RSA public key or key pair.248    """249 250    _only_public = False251    _initialized = True252 253    def __init__(self) -> None:254        pkey = _lib.EVP_PKEY_new()255        self._pkey = _ffi.gc(pkey, _lib.EVP_PKEY_free)256        self._initialized = False257 258    def to_cryptography_key(self) -> _Key:259        """260        Export as a ``cryptography`` key.261 262        :rtype: One of ``cryptography``'s `key interfaces`_.263 264        .. _key interfaces: https://cryptography.io/en/latest/hazmat/\265            primitives/asymmetric/rsa/#key-interfaces266 267        .. versionadded:: 16.1.0268        """269        from cryptography.hazmat.primitives.serialization import (270            load_der_private_key,271            load_der_public_key,272        )273 274        if self._only_public:275            der = dump_publickey(FILETYPE_ASN1, self)276            return typing.cast(_Key, load_der_public_key(der))277        else:278            der = dump_privatekey(FILETYPE_ASN1, self)279            return typing.cast(_Key, load_der_private_key(der, password=None))280 281    @classmethod282    def from_cryptography_key(cls, crypto_key: _Key) -> PKey:283        """284        Construct based on a ``cryptography`` *crypto_key*.285 286        :param crypto_key: A ``cryptography`` key.287        :type crypto_key: One of ``cryptography``'s `key interfaces`_.288 289        :rtype: PKey290 291        .. versionadded:: 16.1.0292        """293        if not isinstance(294            crypto_key,295            (296                dsa.DSAPrivateKey,297                dsa.DSAPublicKey,298                ec.EllipticCurvePrivateKey,299                ec.EllipticCurvePublicKey,300                ed25519.Ed25519PrivateKey,301                ed25519.Ed25519PublicKey,302                ed448.Ed448PrivateKey,303                ed448.Ed448PublicKey,304                rsa.RSAPrivateKey,305                rsa.RSAPublicKey,306            ),307        ):308            raise TypeError("Unsupported key type")309 310        from cryptography.hazmat.primitives.serialization import (311            Encoding,312            NoEncryption,313            PrivateFormat,314            PublicFormat,315        )316 317        if isinstance(318            crypto_key,319            (320                dsa.DSAPublicKey,321                ec.EllipticCurvePublicKey,322                ed25519.Ed25519PublicKey,323                ed448.Ed448PublicKey,324                rsa.RSAPublicKey,325            ),326        ):327            return load_publickey(328                FILETYPE_ASN1,329                crypto_key.public_bytes(330                    Encoding.DER, PublicFormat.SubjectPublicKeyInfo331                ),332            )333        else:334            der = crypto_key.private_bytes(335                Encoding.DER, PrivateFormat.PKCS8, NoEncryption()336            )337            return load_privatekey(FILETYPE_ASN1, der)338 339    def generate_key(self, type: int, bits: int) -> None:340        """341        Generate a key pair of the given type, with the given number of bits.342 343        This generates a key "into" the this object.344 345        :param type: The key type.346        :type type: :py:data:`TYPE_RSA` or :py:data:`TYPE_DSA`347        :param bits: The number of bits.348        :type bits: :py:data:`int` ``>= 0``349        :raises TypeError: If :py:data:`type` or :py:data:`bits` isn't350            of the appropriate type.351        :raises ValueError: If the number of bits isn't an integer of352            the appropriate size.353        :return: ``None``354        """355        if not isinstance(type, int):356            raise TypeError("type must be an integer")357 358        if not isinstance(bits, int):359            raise TypeError("bits must be an integer")360 361        if type == TYPE_RSA:362            if bits <= 0:363                raise ValueError("Invalid number of bits")364 365            # TODO Check error return366            exponent = _lib.BN_new()367            exponent = _ffi.gc(exponent, _lib.BN_free)368            _lib.BN_set_word(exponent, _lib.RSA_F4)369 370            rsa = _lib.RSA_new()371 372            result = _lib.RSA_generate_key_ex(rsa, bits, exponent, _ffi.NULL)373            _openssl_assert(result == 1)374 375            result = _lib.EVP_PKEY_assign_RSA(self._pkey, rsa)376            _openssl_assert(result == 1)377 378        elif type == TYPE_DSA:379            dsa = _lib.DSA_new()380            _openssl_assert(dsa != _ffi.NULL)381 382            dsa = _ffi.gc(dsa, _lib.DSA_free)383            res = _lib.DSA_generate_parameters_ex(384                dsa, bits, _ffi.NULL, 0, _ffi.NULL, _ffi.NULL, _ffi.NULL385            )386            _openssl_assert(res == 1)387 388            _openssl_assert(_lib.DSA_generate_key(dsa) == 1)389            _openssl_assert(_lib.EVP_PKEY_set1_DSA(self._pkey, dsa) == 1)390        else:391            raise Error("No such key type")392 393        self._initialized = True394 395    def check(self) -> bool:396        """397        Check the consistency of an RSA private key.398 399        This is the Python equivalent of OpenSSL's ``RSA_check_key``.400 401        :return: ``True`` if key is consistent.402 403        :raise OpenSSL.crypto.Error: if the key is inconsistent.404 405        :raise TypeError: if the key is of a type which cannot be checked.406            Only RSA keys can currently be checked.407        """408        if self._only_public:409            raise TypeError("public key only")410 411        if _lib.EVP_PKEY_type(self.type()) != _lib.EVP_PKEY_RSA:412            raise TypeError("Only RSA keys can currently be checked.")413 414        rsa = _lib.EVP_PKEY_get1_RSA(self._pkey)415        rsa = _ffi.gc(rsa, _lib.RSA_free)416        result = _lib.RSA_check_key(rsa)417        if result == 1:418            return True419        _raise_current_error()420 421    def type(self) -> int:422        """423        Returns the type of the key424 425        :return: The type of the key.426        """427        return _lib.EVP_PKEY_id(self._pkey)428 429    def bits(self) -> int:430        """431        Returns the number of bits of the key432 433        :return: The number of bits of the key.434        """435        return _lib.EVP_PKEY_bits(self._pkey)436 437 438class _EllipticCurve:439    """440    A representation of a supported elliptic curve.441 442    @cvar _curves: :py:obj:`None` until an attempt is made to load the curves.443        Thereafter, a :py:type:`set` containing :py:type:`_EllipticCurve`444        instances each of which represents one curve supported by the system.445    @type _curves: :py:type:`NoneType` or :py:type:`set`446    """447 448    _curves = None449 450    def __ne__(self, other: Any) -> bool:451        """452        Implement cooperation with the right-hand side argument of ``!=``.453 454        Python 3 seems to have dropped this cooperation in this very narrow455        circumstance.456        """457        if isinstance(other, _EllipticCurve):458            return super().__ne__(other)459        return NotImplemented460 461    @classmethod462    def _load_elliptic_curves(cls, lib: Any) -> set[_EllipticCurve]:463        """464        Get the curves supported by OpenSSL.465 466        :param lib: The OpenSSL library binding object.467 468        :return: A :py:type:`set` of ``cls`` instances giving the names of the469            elliptic curves the underlying library supports.470        """471        num_curves = lib.EC_get_builtin_curves(_ffi.NULL, 0)472        builtin_curves = _ffi.new("EC_builtin_curve[]", num_curves)473        # The return value on this call should be num_curves again.  We474        # could check it to make sure but if it *isn't* then.. what could475        # we do? Abort the whole process, I suppose...?  -exarkun476        lib.EC_get_builtin_curves(builtin_curves, num_curves)477        return set(cls.from_nid(lib, c.nid) for c in builtin_curves)478 479    @classmethod480    def _get_elliptic_curves(cls, lib: Any) -> set[_EllipticCurve]:481        """482        Get, cache, and return the curves supported by OpenSSL.483 484        :param lib: The OpenSSL library binding object.485 486        :return: A :py:type:`set` of ``cls`` instances giving the names of the487            elliptic curves the underlying library supports.488        """489        if cls._curves is None:490            cls._curves = cls._load_elliptic_curves(lib)491        return cls._curves492 493    @classmethod494    def from_nid(cls, lib: Any, nid: int) -> _EllipticCurve:495        """496        Instantiate a new :py:class:`_EllipticCurve` associated with the given497        OpenSSL NID.498 499        :param lib: The OpenSSL library binding object.500 501        :param nid: The OpenSSL NID the resulting curve object will represent.502            This must be a curve NID (and not, for example, a hash NID) or503            subsequent operations will fail in unpredictable ways.504        :type nid: :py:class:`int`505 506        :return: The curve object.507        """508        return cls(lib, nid, _ffi.string(lib.OBJ_nid2sn(nid)).decode("ascii"))509 510    def __init__(self, lib: Any, nid: int, name: str) -> None:511        """512        :param _lib: The :py:mod:`cryptography` binding instance used to513            interface with OpenSSL.514 515        :param _nid: The OpenSSL NID identifying the curve this object516            represents.517        :type _nid: :py:class:`int`518 519        :param name: The OpenSSL short name identifying the curve this object520            represents.521        :type name: :py:class:`unicode`522        """523        self._lib = lib524        self._nid = nid525        self.name = name526 527    def __repr__(self) -> str:528        return f"<Curve {self.name!r}>"529 530    def _to_EC_KEY(self) -> Any:531        """532        Create a new OpenSSL EC_KEY structure initialized to use this curve.533 534        The structure is automatically garbage collected when the Python object535        is garbage collected.536        """537        key = self._lib.EC_KEY_new_by_curve_name(self._nid)538        return _ffi.gc(key, _lib.EC_KEY_free)539 540 541@deprecated(542    "get_elliptic_curves is deprecated. You should use the APIs in "543    "cryptography instead."544)545def get_elliptic_curves() -> set[_EllipticCurve]:546    """547    Return a set of objects representing the elliptic curves supported in the548    OpenSSL build in use.549 550    The curve objects have a :py:class:`unicode` ``name`` attribute by which551    they identify themselves.552 553    The curve objects are useful as values for the argument accepted by554    :py:meth:`Context.set_tmp_ecdh` to specify which elliptical curve should be555    used for ECDHE key exchange.556    """557    return _EllipticCurve._get_elliptic_curves(_lib)558 559 560@deprecated(561    "get_elliptic_curve is deprecated. You should use the APIs in "562    "cryptography instead."563)564def get_elliptic_curve(name: str) -> _EllipticCurve:565    """566    Return a single curve object selected by name.567 568    See :py:func:`get_elliptic_curves` for information about curve objects.569 570    :param name: The OpenSSL short name identifying the curve object to571        retrieve.572    :type name: :py:class:`unicode`573 574    If the named curve is not supported then :py:class:`ValueError` is raised.575    """576    for curve in get_elliptic_curves():577        if curve.name == name:578            return curve579    raise ValueError("unknown curve name", name)580 581 582@functools.total_ordering583class X509Name:584    """585    An X.509 Distinguished Name.586 587    :ivar countryName: The country of the entity.588    :ivar C: Alias for  :py:attr:`countryName`.589 590    :ivar stateOrProvinceName: The state or province of the entity.591    :ivar ST: Alias for :py:attr:`stateOrProvinceName`.592 593    :ivar localityName: The locality of the entity.594    :ivar L: Alias for :py:attr:`localityName`.595 596    :ivar organizationName: The organization name of the entity.597    :ivar O: Alias for :py:attr:`organizationName`.598 599    :ivar organizationalUnitName: The organizational unit of the entity.600    :ivar OU: Alias for :py:attr:`organizationalUnitName`601 602    :ivar commonName: The common name of the entity.603    :ivar CN: Alias for :py:attr:`commonName`.604 605    :ivar emailAddress: The e-mail address of the entity.606    """607 608    def __init__(self, name: X509Name) -> None:609        """610        Create a new X509Name, copying the given X509Name instance.611 612        :param name: The name to copy.613        :type name: :py:class:`X509Name`614        """615        name = _lib.X509_NAME_dup(name._name)616        self._name: Any = _ffi.gc(name, _lib.X509_NAME_free)617 618    def __setattr__(self, name: str, value: Any) -> None:619        if name.startswith("_"):620            return super().__setattr__(name, value)621 622        # Note: we really do not want str subclasses here, so we do not use623        # isinstance.624        if type(name) is not str:625            raise TypeError(626                f"attribute name must be string, not "627                f"'{type(value).__name__:.200}'"628            )629 630        nid = _lib.OBJ_txt2nid(_byte_string(name))631        if nid == _lib.NID_undef:632            try:633                _raise_current_error()634            except Error:635                pass636            raise AttributeError("No such attribute")637 638        # If there's an old entry for this NID, remove it639        for i in range(_lib.X509_NAME_entry_count(self._name)):640            ent = _lib.X509_NAME_get_entry(self._name, i)641            ent_obj = _lib.X509_NAME_ENTRY_get_object(ent)642            ent_nid = _lib.OBJ_obj2nid(ent_obj)643            if nid == ent_nid:644                ent = _lib.X509_NAME_delete_entry(self._name, i)645                _lib.X509_NAME_ENTRY_free(ent)646                break647 648        if isinstance(value, str):649            value = value.encode("utf-8")650 651        add_result = _lib.X509_NAME_add_entry_by_NID(652            self._name, nid, _lib.MBSTRING_UTF8, value, len(value), -1, 0653        )654        if not add_result:655            _raise_current_error()656 657    def __getattr__(self, name: str) -> str | None:658        """659        Find attribute. An X509Name object has the following attributes:660        countryName (alias C), stateOrProvince (alias ST), locality (alias L),661        organization (alias O), organizationalUnit (alias OU), commonName662        (alias CN) and more...663        """664        nid = _lib.OBJ_txt2nid(_byte_string(name))665        if nid == _lib.NID_undef:666            # This is a bit weird.  OBJ_txt2nid indicated failure, but it seems667            # a lower level function, a2d_ASN1_OBJECT, also feels the need to668            # push something onto the error queue.  If we don't clean that up669            # now, someone else will bump into it later and be quite confused.670            # See lp#314814.671            try:672                _raise_current_error()673            except Error:674                pass675            raise AttributeError("No such attribute")676 677        entry_index = _lib.X509_NAME_get_index_by_NID(self._name, nid, -1)678        if entry_index == -1:679            return None680 681        entry = _lib.X509_NAME_get_entry(self._name, entry_index)682        data = _lib.X509_NAME_ENTRY_get_data(entry)683 684        result_buffer = _ffi.new("unsigned char**")685        data_length = _lib.ASN1_STRING_to_UTF8(result_buffer, data)686        _openssl_assert(data_length >= 0)687 688        try:689            result = _ffi.buffer(result_buffer[0], data_length)[:].decode(690                "utf-8"691            )692        finally:693            # XXX untested694            _lib.OPENSSL_free(result_buffer[0])695        return result696 697    def __eq__(self, other: Any) -> bool:698        if not isinstance(other, X509Name):699            return NotImplemented700 701        return _lib.X509_NAME_cmp(self._name, other._name) == 0702 703    def __lt__(self, other: Any) -> bool:704        if not isinstance(other, X509Name):705            return NotImplemented706 707        return _lib.X509_NAME_cmp(self._name, other._name) < 0708 709    def __repr__(self) -> str:710        """711        String representation of an X509Name712        """713        result_buffer = _ffi.new("char[]", 512)714        format_result = _lib.X509_NAME_oneline(715            self._name, result_buffer, len(result_buffer)716        )717        _openssl_assert(format_result != _ffi.NULL)718 719        return "<X509Name object '{}'>".format(720            _ffi.string(result_buffer).decode("utf-8"),721        )722 723    def hash(self) -> int:724        """725        Return an integer representation of the first four bytes of the726        MD5 digest of the DER representation of the name.727 728        This is the Python equivalent of OpenSSL's ``X509_NAME_hash``.729 730        :return: The (integer) hash of this name.731        :rtype: :py:class:`int`732        """733        return _lib.X509_NAME_hash(self._name)734 735    def der(self) -> bytes:736        """737        Return the DER encoding of this name.738 739        :return: The DER encoded form of this name.740        :rtype: :py:class:`bytes`741        """742        result_buffer = _ffi.new("unsigned char**")743        encode_result = _lib.i2d_X509_NAME(self._name, result_buffer)744        _openssl_assert(encode_result >= 0)745 746        string_result = _ffi.buffer(result_buffer[0], encode_result)[:]747        _lib.OPENSSL_free(result_buffer[0])748        return string_result749 750    def get_components(self) -> list[tuple[bytes, bytes]]:751        """752        Returns the components of this name, as a sequence of 2-tuples.753 754        :return: The components of this name.755        :rtype: :py:class:`list` of ``name, value`` tuples.756        """757        result = []758        for i in range(_lib.X509_NAME_entry_count(self._name)):759            ent = _lib.X509_NAME_get_entry(self._name, i)760 761            fname = _lib.X509_NAME_ENTRY_get_object(ent)762            fval = _lib.X509_NAME_ENTRY_get_data(ent)763 764            nid = _lib.OBJ_obj2nid(fname)765            name = _lib.OBJ_nid2sn(nid)766 767            # ffi.string does not handle strings containing NULL bytes768            # (which may have been generated by old, broken software)769            value = _ffi.buffer(770                _lib.ASN1_STRING_get0_data(fval), _lib.ASN1_STRING_length(fval)771            )[:]772            result.append((_ffi.string(name), value))773 774        return result775 776 777@deprecated(778    "CSR support in pyOpenSSL is deprecated. You should use the APIs "779    "in cryptography."780)781class X509Req:782    """783    An X.509 certificate signing requests.784 785    .. deprecated:: 24.2.0786       Use `cryptography.x509.CertificateSigningRequest` instead.787    """788 789    def __init__(self) -> None:790        req = _lib.X509_REQ_new()791        self._req = _ffi.gc(req, _lib.X509_REQ_free)792        # Default to version 0.793        self.set_version(0)794 795    def to_cryptography(self) -> x509.CertificateSigningRequest:796        """797        Export as a ``cryptography`` certificate signing request.798 799        :rtype: ``cryptography.x509.CertificateSigningRequest``800 801        .. versionadded:: 17.1.0802        """803        from cryptography.x509 import load_der_x509_csr804 805        der = _dump_certificate_request_internal(FILETYPE_ASN1, self)806 807        return load_der_x509_csr(der)808 809    @classmethod810    def from_cryptography(811        cls, crypto_req: x509.CertificateSigningRequest812    ) -> X509Req:813        """814        Construct based on a ``cryptography`` *crypto_req*.815 816        :param crypto_req: A ``cryptography`` X.509 certificate signing request817        :type crypto_req: ``cryptography.x509.CertificateSigningRequest``818 819        :rtype: X509Req820 821        .. versionadded:: 17.1.0822        """823        if not isinstance(crypto_req, x509.CertificateSigningRequest):824            raise TypeError("Must be a certificate signing request")825 826        from cryptography.hazmat.primitives.serialization import Encoding827 828        der = crypto_req.public_bytes(Encoding.DER)829        return _load_certificate_request_internal(FILETYPE_ASN1, der)830 831    def set_pubkey(self, pkey: PKey) -> None:832        """833        Set the public key of the certificate signing request.834 835        :param pkey: The public key to use.836        :type pkey: :py:class:`PKey`837 838        :return: ``None``839        """840        set_result = _lib.X509_REQ_set_pubkey(self._req, pkey._pkey)841        _openssl_assert(set_result == 1)842 843    def get_pubkey(self) -> PKey:844        """845        Get the public key of the certificate signing request.846 847        :return: The public key.848        :rtype: :py:class:`PKey`849        """850        pkey = PKey.__new__(PKey)851        pkey._pkey = _lib.X509_REQ_get_pubkey(self._req)852        _openssl_assert(pkey._pkey != _ffi.NULL)853        pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)854        pkey._only_public = True855        return pkey856 857    def set_version(self, version: int) -> None:858        """859        Set the version subfield (RFC 2986, section 4.1) of the certificate860        request.861 862        :param int version: The version number.863        :return: ``None``864        """865        if not isinstance(version, int):866            raise TypeError("version must be an int")867        if version != 0:868            raise ValueError(869                "Invalid version. The only valid version for X509Req is 0."870            )871        set_result = _lib.X509_REQ_set_version(self._req, version)872        _openssl_assert(set_result == 1)873 874    def get_version(self) -> int:875        """876        Get the version subfield (RFC 2459, section 4.1.2.1) of the certificate877        request.878 879        :return: The value of the version subfield.880        :rtype: :py:class:`int`881        """882        return _lib.X509_REQ_get_version(self._req)883 884    def get_subject(self) -> X509Name:885        """886        Return the subject of this certificate signing request.887 888        This creates a new :class:`X509Name` that wraps the underlying subject889        name field on the certificate signing request. Modifying it will modify890        the underlying signing request, and will have the effect of modifying891        any other :class:`X509Name` that refers to this subject.892 893        :return: The subject of this certificate signing request.894        :rtype: :class:`X509Name`895        """896        name = X509Name.__new__(X509Name)897        name._name = _lib.X509_REQ_get_subject_name(self._req)898        _openssl_assert(name._name != _ffi.NULL)899 900        # The name is owned by the X509Req structure.  As long as the X509Name901        # Python object is alive, keep the X509Req Python object alive.902        name._owner = self903 904        return name905 906    def sign(self, pkey: PKey, digest: str) -> None:907        """908        Sign the certificate signing request with this key and digest type.909 910        :param pkey: The key pair to sign with.911        :type pkey: :py:class:`PKey`912        :param digest: The name of the message digest to use for the signature,913            e.g. :py:data:`"sha256"`.914        :type digest: :py:class:`str`915        :return: ``None``916        """917        if pkey._only_public:918            raise ValueError("Key has only public part")919 920        if not pkey._initialized:921            raise ValueError("Key is uninitialized")922 923        digest_obj = _lib.EVP_get_digestbyname(_byte_string(digest))924        if digest_obj == _ffi.NULL:925            raise ValueError("No such digest method")926 927        sign_result = _lib.X509_REQ_sign(self._req, pkey._pkey, digest_obj)928        _openssl_assert(sign_result > 0)929 930    def verify(self, pkey: PKey) -> bool:931        """932        Verifies the signature on this certificate signing request.933 934        :param PKey key: A public key.935 936        :return: ``True`` if the signature is correct.937        :rtype: bool938 939        :raises OpenSSL.crypto.Error: If the signature is invalid or there is a940            problem verifying the signature.941        """942        if not isinstance(pkey, PKey):943            raise TypeError("pkey must be a PKey instance")944 945        result = _lib.X509_REQ_verify(self._req, pkey._pkey)946        if result <= 0:947            _raise_current_error()948 949        return result950 951 952class X509:953    """954    An X.509 certificate.955    """956 957    def __init__(self) -> None:958        x509 = _lib.X509_new()959        _openssl_assert(x509 != _ffi.NULL)960        self._x509 = _ffi.gc(x509, _lib.X509_free)961 962        self._issuer_invalidator = _X509NameInvalidator()963        self._subject_invalidator = _X509NameInvalidator()964 965    @classmethod966    def _from_raw_x509_ptr(cls, x509: Any) -> X509:967        cert = cls.__new__(cls)968        cert._x509 = _ffi.gc(x509, _lib.X509_free)969        cert._issuer_invalidator = _X509NameInvalidator()970        cert._subject_invalidator = _X509NameInvalidator()971        return cert972 973    def to_cryptography(self) -> x509.Certificate:974        """975        Export as a ``cryptography`` certificate.976 977        :rtype: ``cryptography.x509.Certificate``978 979        .. versionadded:: 17.1.0980        """981        from cryptography.x509 import load_der_x509_certificate982 983        der = dump_certificate(FILETYPE_ASN1, self)984        return load_der_x509_certificate(der)985 986    @classmethod987    def from_cryptography(cls, crypto_cert: x509.Certificate) -> X509:988        """989        Construct based on a ``cryptography`` *crypto_cert*.990 991        :param crypto_key: A ``cryptography`` X.509 certificate.992        :type crypto_key: ``cryptography.x509.Certificate``993 994        :rtype: X509995 996        .. versionadded:: 17.1.0997        """998        if not isinstance(crypto_cert, x509.Certificate):999            raise TypeError("Must be a certificate")1000 1001        from cryptography.hazmat.primitives.serialization import Encoding1002 1003        der = crypto_cert.public_bytes(Encoding.DER)1004        return load_certificate(FILETYPE_ASN1, der)1005 1006    def set_version(self, version: int) -> None:1007        """1008        Set the version number of the certificate. Note that the1009        version value is zero-based, eg. a value of 0 is V1.1010 1011        :param version: The version number of the certificate.1012        :type version: :py:class:`int`1013 1014        :return: ``None``1015        """1016        if not isinstance(version, int):1017            raise TypeError("version must be an integer")1018 1019        _openssl_assert(_lib.X509_set_version(self._x509, version) == 1)1020 1021    def get_version(self) -> int:1022        """1023        Return the version number of the certificate.1024 1025        :return: The version number of the certificate.1026        :rtype: :py:class:`int`1027        """1028        return _lib.X509_get_version(self._x509)1029 1030    def get_pubkey(self) -> PKey:1031        """1032        Get the public key of the certificate.1033 1034        :return: The public key.1035        :rtype: :py:class:`PKey`1036        """1037        pkey = PKey.__new__(PKey)1038        pkey._pkey = _lib.X509_get_pubkey(self._x509)1039        if pkey._pkey == _ffi.NULL:1040            _raise_current_error()1041        pkey._pkey = _ffi.gc(pkey._pkey, _lib.EVP_PKEY_free)1042        pkey._only_public = True1043        return pkey1044 1045    def set_pubkey(self, pkey: PKey) -> None:1046        """1047        Set the public key of the certificate.1048 1049        :param pkey: The public key.1050        :type pkey: :py:class:`PKey`1051 1052        :return: :py:data:`None`1053        """1054        if not isinstance(pkey, PKey):1055            raise TypeError("pkey must be a PKey instance")1056 1057        set_result = _lib.X509_set_pubkey(self._x509, pkey._pkey)1058        _openssl_assert(set_result == 1)1059 1060    def sign(self, pkey: PKey, digest: str) -> None:1061        """1062        Sign the certificate with this key and digest type.1063 1064        :param pkey: The key to sign with.1065        :type pkey: :py:class:`PKey`1066 1067        :param digest: The name of the message digest to use.1068        :type digest: :py:class:`str`1069 1070        :return: :py:data:`None`1071        """1072        if not isinstance(pkey, PKey):1073            raise TypeError("pkey must be a PKey instance")1074 1075        if pkey._only_public:1076            raise ValueError("Key only has public part")1077 1078        if not pkey._initialized:1079            raise ValueError("Key is uninitialized")1080 1081        evp_md = _lib.EVP_get_digestbyname(_byte_string(digest))1082        if evp_md == _ffi.NULL:1083            raise ValueError("No such digest method")1084 1085        sign_result = _lib.X509_sign(self._x509, pkey._pkey, evp_md)1086        _openssl_assert(sign_result > 0)1087 1088    def get_signature_algorithm(self) -> bytes:1089        """1090        Return the signature algorithm used in the certificate.1091 1092        :return: The name of the algorithm.1093        :rtype: :py:class:`bytes`1094 1095        :raises ValueError: If the signature algorithm is undefined.1096 1097        .. versionadded:: 0.131098        """1099        sig_alg = _lib.X509_get0_tbs_sigalg(self._x509)1100        alg = _ffi.new("ASN1_OBJECT **")1101        _lib.X509_ALGOR_get0(alg, _ffi.NULL, _ffi.NULL, sig_alg)1102        nid = _lib.OBJ_obj2nid(alg[0])1103        if nid == _lib.NID_undef:1104            raise ValueError("Undefined signature algorithm")1105        return _ffi.string(_lib.OBJ_nid2ln(nid))1106 1107    def digest(self, digest_name: str) -> bytes:1108        """1109        Return the digest of the X509 object.1110 1111        :param digest_name: The name of the digest algorithm to use.1112        :type digest_name: :py:class:`str`1113 1114        :return: The digest of the object, formatted as1115            :py:const:`b":"`-delimited hex pairs.1116        :rtype: :py:class:`bytes`1117        """1118        digest = _lib.EVP_get_digestbyname(_byte_string(digest_name))1119        if digest == _ffi.NULL:1120            raise ValueError("No such digest method")1121 1122        result_buffer = _ffi.new("unsigned char[]", _lib.EVP_MAX_MD_SIZE)1123        result_length = _ffi.new("unsigned int[]", 1)1124        result_length[0] = len(result_buffer)1125 1126        digest_result = _lib.X509_digest(1127            self._x509, digest, result_buffer, result_length1128        )1129        _openssl_assert(digest_result == 1)1130 1131        return b":".join(1132            [1133                b16encode(ch).upper()1134                for ch in _ffi.buffer(result_buffer, result_length[0])1135            ]1136        )1137 1138    def subject_name_hash(self) -> int:1139        """1140        Return the hash of the X509 subject.1141 1142        :return: The hash of the subject.1143        :rtype: :py:class:`int`1144        """1145        return _lib.X509_subject_name_hash(self._x509)1146 1147    def set_serial_number(self, serial: int) -> None:1148        """1149        Set the serial number of the certificate.1150 1151        :param serial: The new serial number.1152        :type serial: :py:class:`int`1153 1154        :return: :py:data`None`1155        """1156        if not isinstance(serial, int):1157            raise TypeError("serial must be an integer")1158 1159        hex_serial = hex(serial)[2:]1160        hex_serial_bytes = hex_serial.encode("ascii")1161 1162        bignum_serial = _ffi.new("BIGNUM**")1163 1164        # BN_hex2bn stores the result in &bignum.1165        result = _lib.BN_hex2bn(bignum_serial, hex_serial_bytes)1166        _openssl_assert(result != _ffi.NULL)1167 1168        asn1_serial = _lib.BN_to_ASN1_INTEGER(bignum_serial[0], _ffi.NULL)1169        _lib.BN_free(bignum_serial[0])1170        _openssl_assert(asn1_serial != _ffi.NULL)1171        asn1_serial = _ffi.gc(asn1_serial, _lib.ASN1_INTEGER_free)1172        set_result = _lib.X509_set_serialNumber(self._x509, asn1_serial)1173        _openssl_assert(set_result == 1)1174 1175    def get_serial_number(self) -> int:1176        """1177        Return the serial number of this certificate.1178 1179        :return: The serial number.1180        :rtype: int1181        """1182        asn1_serial = _lib.X509_get_serialNumber(self._x509)1183        bignum_serial = _lib.ASN1_INTEGER_to_BN(asn1_serial, _ffi.NULL)1184        try:1185            hex_serial = _lib.BN_bn2hex(bignum_serial)1186            try:1187                hexstring_serial = _ffi.string(hex_serial)1188                serial = int(hexstring_serial, 16)1189                return serial1190            finally:1191                _lib.OPENSSL_free(hex_serial)1192        finally:1193            _lib.BN_free(bignum_serial)1194 1195    def gmtime_adj_notAfter(self, amount: int) -> None:1196        """1197        Adjust the time stamp on which the certificate stops being valid.1198 1199        :param int amount: The number of seconds by which to adjust the1200            timestamp.

Showing the first 1,200 of 2146 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai