Skip to content

Commit c5c3a04

Browse files
committed
Remove X509Extension, which has been deprecated for a year
1 parent 6e43ae1 commit c5c3a04

4 files changed

Lines changed: 3 additions & 637 deletions

File tree

CHANGELOG.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ Changes:
7979
Backward-incompatible changes:
8080
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8181

82+
- Removed deprecated ``OpenSSL.crypto.X509Extension``, ``OpenSSL.crypto.X509Req.add_extension``, ``OpenSSL.crypto.X509Req.get_extensions``, ``OpenSSL.crypto.X509.add_extension``, ``OpenSSL.crypto.X509.get_extensions``. ``cryptography.x509`` should be used instead.
83+
8284
Deprecations:
8385
^^^^^^^^^^^^^
8486

doc/api/crypto.rst

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -148,16 +148,6 @@ PKey objects
148148
149149
Key type constants.
150150

151-
.. _openssl-509ext:
152-
153-
X509Extension objects
154-
---------------------
155-
156-
.. autoclass:: X509Extension
157-
:members:
158-
:special-members:
159-
:exclude-members: __weakref__
160-
161151
Exceptions
162152
----------
163153

src/OpenSSL/crypto.py

Lines changed: 1 addition & 308 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
55
import functools
66
import sys
77
import typing
8-
import warnings
98
from base64 import b16encode
10-
from collections.abc import Iterable, Sequence
9+
from collections.abc import Sequence
1110
from functools import partial
1211
from typing import (
1312
Any,
@@ -63,7 +62,6 @@ def deprecated(msg: str, **kwargs: object) -> Callable[[_T], _T]:
6362
"X509",
6463
"Error",
6564
"PKey",
66-
"X509Extension",
6765
"X509Name",
6866
"X509Req",
6967
"X509Store",
@@ -776,182 +774,6 @@ def get_components(self) -> list[tuple[bytes, bytes]]:
776774
return result
777775

778776

779-
@deprecated(
780-
"X509Extension support in pyOpenSSL is deprecated. You should use the "
781-
"APIs in cryptography."
782-
)
783-
class X509Extension:
784-
"""
785-
An X.509 v3 certificate extension.
786-
787-
.. deprecated:: 23.3.0
788-
Use cryptography's X509 APIs instead.
789-
"""
790-
791-
def __init__(
792-
self,
793-
type_name: bytes,
794-
critical: bool,
795-
value: bytes,
796-
subject: X509 | None = None,
797-
issuer: X509 | None = None,
798-
) -> None:
799-
"""
800-
Initializes an X509 extension.
801-
802-
:param type_name: The name of the type of extension_ to create.
803-
:type type_name: :py:data:`bytes`
804-
805-
:param bool critical: A flag indicating whether this is a critical
806-
extension.
807-
808-
:param value: The OpenSSL textual representation of the extension's
809-
value.
810-
:type value: :py:data:`bytes`
811-
812-
:param subject: Optional X509 certificate to use as subject.
813-
:type subject: :py:class:`X509`
814-
815-
:param issuer: Optional X509 certificate to use as issuer.
816-
:type issuer: :py:class:`X509`
817-
818-
.. _extension: https://www.openssl.org/docs/manmaster/man5/
819-
x509v3_config.html#STANDARD-EXTENSIONS
820-
"""
821-
ctx = _ffi.new("X509V3_CTX*")
822-
823-
# A context is necessary for any extension which uses the r2i
824-
# conversion method. That is, X509V3_EXT_nconf may segfault if passed
825-
# a NULL ctx. Start off by initializing most of the fields to NULL.
826-
_lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0)
827-
828-
# We have no configuration database - but perhaps we should (some
829-
# extensions may require it).
830-
_lib.X509V3_set_ctx_nodb(ctx)
831-
832-
# Initialize the subject and issuer, if appropriate. ctx is a local,
833-
# and as far as I can tell none of the X509V3_* APIs invoked here steal
834-
# any references, so no need to mess with reference counts or
835-
# duplicates.
836-
if issuer is not None:
837-
if not isinstance(issuer, X509):
838-
raise TypeError("issuer must be an X509 instance")
839-
ctx.issuer_cert = issuer._x509
840-
if subject is not None:
841-
if not isinstance(subject, X509):
842-
raise TypeError("subject must be an X509 instance")
843-
ctx.subject_cert = subject._x509
844-
845-
if critical:
846-
# There are other OpenSSL APIs which would let us pass in critical
847-
# separately, but they're harder to use, and since value is already
848-
# a pile of crappy junk smuggling a ton of utterly important
849-
# structured data, what's the point of trying to avoid nasty stuff
850-
# with strings? (However, X509V3_EXT_i2d in particular seems like
851-
# it would be a better API to invoke. I do not know where to get
852-
# the ext_struc it desires for its last parameter, though.)
853-
value = b"critical," + value
854-
855-
extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value)
856-
if extension == _ffi.NULL:
857-
_raise_current_error()
858-
self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
859-
860-
@property
861-
def _nid(self) -> Any:
862-
return _lib.OBJ_obj2nid(
863-
_lib.X509_EXTENSION_get_object(self._extension)
864-
)
865-
866-
_prefixes: typing.ClassVar[dict[int, str]] = {
867-
_lib.GEN_EMAIL: "email",
868-
_lib.GEN_DNS: "DNS",
869-
_lib.GEN_URI: "URI",
870-
}
871-
872-
def _subjectAltNameString(self) -> str:
873-
names = _ffi.cast(
874-
"GENERAL_NAMES*", _lib.X509V3_EXT_d2i(self._extension)
875-
)
876-
877-
names = _ffi.gc(names, _lib.GENERAL_NAMES_free)
878-
parts = []
879-
for i in range(_lib.sk_GENERAL_NAME_num(names)):
880-
name = _lib.sk_GENERAL_NAME_value(names, i)
881-
try:
882-
label = self._prefixes[name.type]
883-
except KeyError:
884-
bio = _new_mem_buf()
885-
_lib.GENERAL_NAME_print(bio, name)
886-
parts.append(_bio_to_string(bio).decode("utf-8"))
887-
else:
888-
asn1_string = _ffi.cast("ASN1_STRING*", name.d.ia5)
889-
value = _ffi.buffer(
890-
_lib.ASN1_STRING_get0_data(asn1_string),
891-
_lib.ASN1_STRING_length(asn1_string),
892-
)[:].decode("utf-8")
893-
parts.append(label + ":" + value)
894-
return ", ".join(parts)
895-
896-
def __str__(self) -> str:
897-
"""
898-
:return: a nice text representation of the extension
899-
"""
900-
if _lib.NID_subject_alt_name == self._nid:
901-
return self._subjectAltNameString()
902-
903-
bio = _new_mem_buf()
904-
print_result = _lib.X509V3_EXT_print(bio, self._extension, 0, 0)
905-
_openssl_assert(print_result != 0)
906-
907-
return _bio_to_string(bio).decode("utf-8")
908-
909-
def get_critical(self) -> bool:
910-
"""
911-
Returns the critical field of this X.509 extension.
912-
913-
:return: The critical field.
914-
"""
915-
return _lib.X509_EXTENSION_get_critical(self._extension)
916-
917-
def get_short_name(self) -> bytes:
918-
"""
919-
Returns the short type name of this X.509 extension.
920-
921-
The result is a byte string such as :py:const:`b"basicConstraints"`.
922-
923-
:return: The short type name.
924-
:rtype: :py:data:`bytes`
925-
926-
.. versionadded:: 0.12
927-
"""
928-
obj = _lib.X509_EXTENSION_get_object(self._extension)
929-
nid = _lib.OBJ_obj2nid(obj)
930-
# OpenSSL 3.1.0 has a bug where nid2sn returns NULL for NIDs that
931-
# previously returned UNDEF. This is a workaround for that issue.
932-
# https://github.com/openssl/openssl/commit/908ba3ed9adbb3df90f76
933-
buf = _lib.OBJ_nid2sn(nid)
934-
if buf != _ffi.NULL:
935-
return _ffi.string(buf)
936-
else:
937-
return b"UNDEF"
938-
939-
def get_data(self) -> bytes:
940-
"""
941-
Returns the data of the X509 extension, encoded as ASN.1.
942-
943-
:return: The ASN.1 encoded data of this X509 extension.
944-
:rtype: :py:data:`bytes`
945-
946-
.. versionadded:: 0.12
947-
"""
948-
octet_result = _lib.X509_EXTENSION_get_data(self._extension)
949-
string_result = _ffi.cast("ASN1_STRING*", octet_result)
950-
char_result = _lib.ASN1_STRING_get0_data(string_result)
951-
result_length = _lib.ASN1_STRING_length(string_result)
952-
return _ffi.buffer(char_result, result_length)[:]
953-
954-
955777
@deprecated(
956778
"CSR support in pyOpenSSL is deprecated. You should use the APIs "
957779
"in cryptography."
@@ -1081,77 +903,6 @@ def get_subject(self) -> X509Name:
1081903

1082904
return name
1083905

1084-
def add_extensions(self, extensions: Iterable[X509Extension]) -> None:
1085-
"""
1086-
Add extensions to the certificate signing request.
1087-
1088-
:param extensions: The X.509 extensions to add.
1089-
:type extensions: iterable of :py:class:`X509Extension`
1090-
:return: ``None``
1091-
"""
1092-
warnings.warn(
1093-
(
1094-
"This API is deprecated and will be removed in a future "
1095-
"version of pyOpenSSL. You should use pyca/cryptography's "
1096-
"X.509 APIs instead."
1097-
),
1098-
DeprecationWarning,
1099-
stacklevel=2,
1100-
)
1101-
1102-
stack = _lib.sk_X509_EXTENSION_new_null()
1103-
_openssl_assert(stack != _ffi.NULL)
1104-
1105-
stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
1106-
1107-
for ext in extensions:
1108-
if not isinstance(ext, X509Extension):
1109-
raise ValueError("One of the elements is not an X509Extension")
1110-
1111-
# TODO push can fail (here and elsewhere)
1112-
_lib.sk_X509_EXTENSION_push(stack, ext._extension)
1113-
1114-
add_result = _lib.X509_REQ_add_extensions(self._req, stack)
1115-
_openssl_assert(add_result == 1)
1116-
1117-
def get_extensions(self) -> list[X509Extension]:
1118-
"""
1119-
Get X.509 extensions in the certificate signing request.
1120-
1121-
:return: The X.509 extensions in this request.
1122-
:rtype: :py:class:`list` of :py:class:`X509Extension` objects.
1123-
1124-
.. versionadded:: 0.15
1125-
"""
1126-
warnings.warn(
1127-
(
1128-
"This API is deprecated and will be removed in a future "
1129-
"version of pyOpenSSL. You should use pyca/cryptography's "
1130-
"X.509 APIs instead."
1131-
),
1132-
DeprecationWarning,
1133-
stacklevel=2,
1134-
)
1135-
1136-
exts = []
1137-
native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
1138-
native_exts_obj = _ffi.gc(
1139-
native_exts_obj,
1140-
lambda x: _lib.sk_X509_EXTENSION_pop_free(
1141-
x,
1142-
_ffi.addressof(_lib._original_lib, "X509_EXTENSION_free"),
1143-
),
1144-
)
1145-
1146-
for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
1147-
ext = X509Extension.__new__(X509Extension)
1148-
extension = _lib.X509_EXTENSION_dup(
1149-
_lib.sk_X509_EXTENSION_value(native_exts_obj, i)
1150-
)
1151-
ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
1152-
exts.append(ext)
1153-
return exts
1154-
1155906
def sign(self, pkey: PKey, digest: str) -> None:
1156907
"""
1157908
Sign the certificate signing request with this key and digest type.
@@ -1629,64 +1380,6 @@ def get_extension_count(self) -> int:
16291380
"""
16301381
return _lib.X509_get_ext_count(self._x509)
16311382

1632-
def add_extensions(self, extensions: Iterable[X509Extension]) -> None:
1633-
"""
1634-
Add extensions to the certificate.
1635-
1636-
:param extensions: The extensions to add.
1637-
:type extensions: An iterable of :py:class:`X509Extension` objects.
1638-
:return: ``None``
1639-
"""
1640-
warnings.warn(
1641-
(
1642-
"This API is deprecated and will be removed in a future "
1643-
"version of pyOpenSSL. You should use pyca/cryptography's "
1644-
"X.509 APIs instead."
1645-
),
1646-
DeprecationWarning,
1647-
stacklevel=2,
1648-
)
1649-
1650-
for ext in extensions:
1651-
if not isinstance(ext, X509Extension):
1652-
raise ValueError("One of the elements is not an X509Extension")
1653-
1654-
add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
1655-
_openssl_assert(add_result == 1)
1656-
1657-
def get_extension(self, index: int) -> X509Extension:
1658-
"""
1659-
Get a specific extension of the certificate by index.
1660-
1661-
Extensions on a certificate are kept in order. The index
1662-
parameter selects which extension will be returned.
1663-
1664-
:param int index: The index of the extension to retrieve.
1665-
:return: The extension at the specified index.
1666-
:rtype: :py:class:`X509Extension`
1667-
:raises IndexError: If the extension index was out of bounds.
1668-
1669-
.. versionadded:: 0.12
1670-
"""
1671-
warnings.warn(
1672-
(
1673-
"This API is deprecated and will be removed in a future "
1674-
"version of pyOpenSSL. You should use pyca/cryptography's "
1675-
"X.509 APIs instead."
1676-
),
1677-
DeprecationWarning,
1678-
stacklevel=2,
1679-
)
1680-
1681-
ext = X509Extension.__new__(X509Extension)
1682-
ext._extension = _lib.X509_get_ext(self._x509, index)
1683-
if ext._extension == _ffi.NULL:
1684-
raise IndexError("extension index out of bounds")
1685-
1686-
extension = _lib.X509_EXTENSION_dup(ext._extension)
1687-
ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
1688-
return ext
1689-
16901383

16911384
class X509StoreFlags:
16921385
"""

0 commit comments

Comments
 (0)