Skip to content

Commit 5a27772

Browse files
committed
Remove X509Extension, which has been deprecated for a year
1 parent 0baa319 commit 5a27772

File tree

4 files changed

+2
-651
lines changed

4 files changed

+2
-651
lines changed

CHANGELOG.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ The third digit is only for regressions.
1010
Backward-incompatible changes:
1111
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1212

13+
- 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``
14+
1315
Deprecations:
1416
^^^^^^^^^^^^^
1517

doc/api/crypto.rst

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -160,16 +160,6 @@ PKey objects
160160
161161
Key type constants.
162162

163-
.. _openssl-509ext:
164-
165-
X509Extension objects
166-
---------------------
167-
168-
.. autoclass:: X509Extension
169-
:members:
170-
:special-members:
171-
:exclude-members: __weakref__
172-
173163
.. _crl:
174164

175165
CRL objects

src/OpenSSL/crypto.py

Lines changed: 0 additions & 316 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44
import datetime
55
import functools
66
import typing
7-
import warnings
87
from base64 import b16encode
98
from functools import partial
109
from os import PathLike
1110
from typing import (
1211
Any,
1312
Callable,
14-
Iterable,
1513
Sequence,
1614
Union,
1715
)
@@ -61,7 +59,6 @@
6159
"Error",
6260
"PKey",
6361
"Revoked",
64-
"X509Extension",
6562
"X509Name",
6663
"X509Req",
6764
"X509Store",
@@ -797,186 +794,6 @@ def get_components(self) -> list[tuple[bytes, bytes]]:
797794
return result
798795

799796

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

1100917
return name
1101918

1102-
def add_extensions(
1103-
self, extensions: Iterable[_X509ExtensionInternal]
1104-
) -> None:
1105-
"""
1106-
Add extensions to the certificate signing request.
1107-
1108-
:param extensions: The X.509 extensions to add.
1109-
:type extensions: iterable of :py:class:`X509Extension`
1110-
:return: ``None``
1111-
"""
1112-
warnings.warn(
1113-
(
1114-
"This API is deprecated and will be removed in a future "
1115-
"version of pyOpenSSL. You should use pyca/cryptography's "
1116-
"X.509 APIs instead."
1117-
),
1118-
DeprecationWarning,
1119-
stacklevel=2,
1120-
)
1121-
1122-
stack = _lib.sk_X509_EXTENSION_new_null()
1123-
_openssl_assert(stack != _ffi.NULL)
1124-
1125-
stack = _ffi.gc(stack, _lib.sk_X509_EXTENSION_free)
1126-
1127-
for ext in extensions:
1128-
if not isinstance(ext, _X509ExtensionInternal):
1129-
raise ValueError("One of the elements is not an X509Extension")
1130-
1131-
# TODO push can fail (here and elsewhere)
1132-
_lib.sk_X509_EXTENSION_push(stack, ext._extension)
1133-
1134-
add_result = _lib.X509_REQ_add_extensions(self._req, stack)
1135-
_openssl_assert(add_result == 1)
1136-
1137-
def get_extensions(self) -> list[_X509ExtensionInternal]:
1138-
"""
1139-
Get X.509 extensions in the certificate signing request.
1140-
1141-
:return: The X.509 extensions in this request.
1142-
:rtype: :py:class:`list` of :py:class:`X509Extension` objects.
1143-
1144-
.. versionadded:: 0.15
1145-
"""
1146-
warnings.warn(
1147-
(
1148-
"This API is deprecated and will be removed in a future "
1149-
"version of pyOpenSSL. You should use pyca/cryptography's "
1150-
"X.509 APIs instead."
1151-
),
1152-
DeprecationWarning,
1153-
stacklevel=2,
1154-
)
1155-
1156-
exts = []
1157-
native_exts_obj = _lib.X509_REQ_get_extensions(self._req)
1158-
native_exts_obj = _ffi.gc(
1159-
native_exts_obj,
1160-
lambda x: _lib.sk_X509_EXTENSION_pop_free(
1161-
x,
1162-
_ffi.addressof(_lib._original_lib, "X509_EXTENSION_free"),
1163-
),
1164-
)
1165-
1166-
for i in range(_lib.sk_X509_EXTENSION_num(native_exts_obj)):
1167-
ext = _X509ExtensionInternal.__new__(_X509ExtensionInternal)
1168-
extension = _lib.X509_EXTENSION_dup(
1169-
_lib.sk_X509_EXTENSION_value(native_exts_obj, i)
1170-
)
1171-
ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
1172-
exts.append(ext)
1173-
return exts
1174-
1175919
def sign(self, pkey: PKey, digest: str) -> None:
1176920
"""
1177921
Sign the certificate signing request with this key and digest type.
@@ -1663,66 +1407,6 @@ def get_extension_count(self) -> int:
16631407
"""
16641408
return _lib.X509_get_ext_count(self._x509)
16651409

1666-
def add_extensions(
1667-
self, extensions: Iterable[_X509ExtensionInternal]
1668-
) -> None:
1669-
"""
1670-
Add extensions to the certificate.
1671-
1672-
:param extensions: The extensions to add.
1673-
:type extensions: An iterable of :py:class:`X509Extension` objects.
1674-
:return: ``None``
1675-
"""
1676-
warnings.warn(
1677-
(
1678-
"This API is deprecated and will be removed in a future "
1679-
"version of pyOpenSSL. You should use pyca/cryptography's "
1680-
"X.509 APIs instead."
1681-
),
1682-
DeprecationWarning,
1683-
stacklevel=2,
1684-
)
1685-
1686-
for ext in extensions:
1687-
if not isinstance(ext, _X509ExtensionInternal):
1688-
raise ValueError("One of the elements is not an X509Extension")
1689-
1690-
add_result = _lib.X509_add_ext(self._x509, ext._extension, -1)
1691-
_openssl_assert(add_result == 1)
1692-
1693-
def get_extension(self, index: int) -> _X509ExtensionInternal:
1694-
"""
1695-
Get a specific extension of the certificate by index.
1696-
1697-
Extensions on a certificate are kept in order. The index
1698-
parameter selects which extension will be returned.
1699-
1700-
:param int index: The index of the extension to retrieve.
1701-
:return: The extension at the specified index.
1702-
:rtype: :py:class:`X509Extension`
1703-
:raises IndexError: If the extension index was out of bounds.
1704-
1705-
.. versionadded:: 0.12
1706-
"""
1707-
warnings.warn(
1708-
(
1709-
"This API is deprecated and will be removed in a future "
1710-
"version of pyOpenSSL. You should use pyca/cryptography's "
1711-
"X.509 APIs instead."
1712-
),
1713-
DeprecationWarning,
1714-
stacklevel=2,
1715-
)
1716-
1717-
ext = _X509ExtensionInternal.__new__(_X509ExtensionInternal)
1718-
ext._extension = _lib.X509_get_ext(self._x509, index)
1719-
if ext._extension == _ffi.NULL:
1720-
raise IndexError("extension index out of bounds")
1721-
1722-
extension = _lib.X509_EXTENSION_dup(ext._extension)
1723-
ext._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
1724-
return ext
1725-
17261410

17271411
class X509StoreFlags:
17281412
"""

0 commit comments

Comments
 (0)