Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package salt for openSUSE:Factory checked in at 2025-11-11 19:19:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/salt (Old) and /work/SRC/openSUSE:Factory/.salt.new.1980 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "salt" Tue Nov 11 19:19:40 2025 rev:186 rq:1317046 version:3006.0 Changes: -------- --- /work/SRC/openSUSE:Factory/salt/salt.changes 2025-10-31 16:28:14.454351074 +0100 +++ /work/SRC/openSUSE:Factory/.salt.new.1980/salt.changes 2025-11-11 19:19:51.455755964 +0100 @@ -1,0 +2,25 @@ +Tue Nov 11 08:02:12 UTC 2025 - Marek Czernek <[email protected]> + +- Fix TLS and x509 modules for OSes with older cryptography module +- Require python-legacy-cgi only for Python > 3.12 + +- Added: + * fix-tls-and-x509-modules-for-older-cryptography-modu.patch + +------------------------------------------------------------------- +Mon Nov 10 09:46:28 UTC 2025 - Marek Czernek <[email protected]> + +- Builds with py >=3.13 require python-legacy-cgi + +------------------------------------------------------------------- +Fri Nov 7 16:36:10 UTC 2025 - Pablo Suárez Hernández <[email protected]> + +- Fix Salt for Python > 3.11 (bsc#1252285) (bsc#1252244) + * Use external tornado on Python > 3.11 + * Make tls and x509 to use python-cryptography + * Remove usage of spwd + +- Added: + * fix-salt-for-python-3.11.patch + +------------------------------------------------------------------- New: ---- fix-salt-for-python-3.11.patch fix-tls-and-x509-modules-for-older-cryptography-modu.patch ----------(New B)---------- New:- Added: * fix-salt-for-python-3.11.patch New:- Added: * fix-tls-and-x509-modules-for-older-cryptography-modu.patch ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ salt.spec ++++++ --- /var/tmp/diff_new_pack.gmQ60X/_old 2025-11-11 19:20:00.644140801 +0100 +++ /var/tmp/diff_new_pack.gmQ60X/_new 2025-11-11 19:20:00.648140969 +0100 @@ -587,6 +587,10 @@ Patch184: use-versioned-python-interpreter-for-salt-ssh.patch # PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/735 Patch185: do-not-break-signature-verification-on-latest-m2cryp.patch +# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/736 +Patch186: fix-salt-for-python-3.11.patch +# PATCH-FIX_OPENSUSE: https://github.com/openSUSE/salt/pull/737 +Patch187: fix-tls-and-x509-modules-for-older-cryptography-modu.patch ### IMPORTANT: The line below is used as a snippet marker. Do not touch it. ### SALT PATCHES LIST END @@ -790,6 +794,7 @@ Requires: %{python_module looseversion} Requires: %{python_module packaging} Requires: %{python_module contextvars} +Requires: %{python_module cryptography} %if 0%{?suse_version} # required for zypper.py Requires: %{python_module rpm} @@ -807,6 +812,7 @@ Requires: python-looseversion Requires: python-packaging Requires: python-contextvars +Requires: python-cryptography %if 0%{?suse_version} # required for zypper.py Requires: python-rpm @@ -847,11 +853,18 @@ Recommends: python-passlib %endif +%if 0%{?suse_version} >= 1600 +Requires: %{python_module tornado} +%if 0%{?python3_version_nodots} > 312 +Requires: %{python_module legacy-cgi} +%endif +%else %if 0%{?singlespec_compat} Provides: bundled(%{python_module tornado}) = 4.5.3 %else Provides: bundled(python-tornado) = 4.5.3 %endif +%endif Provides: %{name}-call = %{version}-%{release} ++++++ _lastrevision ++++++ --- /var/tmp/diff_new_pack.gmQ60X/_old 2025-11-11 19:20:00.760145660 +0100 +++ /var/tmp/diff_new_pack.gmQ60X/_new 2025-11-11 19:20:00.764145827 +0100 @@ -1,3 +1,3 @@ -1fc2dab7f7a83e75c56d06f805cf5dcc25d165cc +c51b56faa8acda43ec37dad57a26fda6303179cf (No newline at EOF) ++++++ fix-salt-for-python-3.11.patch ++++++ ++++ 6675 lines (skipped) ++++++ fix-tls-and-x509-modules-for-older-cryptography-modu.patch ++++++ >From 7f15657c26c4e5e9fabc72f4da2d9a91353d5d3a Mon Sep 17 00:00:00 2001 From: Marek Czernek <[email protected]> Date: Tue, 11 Nov 2025 08:46:20 +0100 Subject: [PATCH] Fix tls and x509 modules for older cryptography module (#737) --- salt/modules/tls.py | 73 +++++++++++++++++------- salt/modules/x509.py | 128 +++++++++++++++++++++++++++++++++++-------- 2 files changed, 158 insertions(+), 43 deletions(-) diff --git a/salt/modules/tls.py b/salt/modules/tls.py index 9d29bd1e9b..4d7db87f93 100644 --- a/salt/modules/tls.py +++ b/salt/modules/tls.py @@ -104,6 +104,7 @@ import logging import math import os import re +import sys import time from datetime import datetime @@ -1594,6 +1595,9 @@ def create_pkcs12(ca_name, CN, passphrase="", cacert_path=None, replace=False): salt '*' tls.create_pkcs12 test localhost """ + # Necessary for OSes with older cryptography module + compat_mode = sys.version_info < (3,12) + set_ca_path(cacert_path) p12_path = f"{cert_base_path()}/{ca_name}/certs/{CN}.p12" ca_cert_path = f"{cert_base_path()}/{ca_name}/{ca_name}_ca_cert.crt" @@ -1605,7 +1609,12 @@ def create_pkcs12(ca_name, CN, passphrase="", cacert_path=None, replace=False): try: with salt.utils.files.fopen(ca_cert_path, "rb") as fhr: - ca_cert = cryptography.x509.load_pem_x509_certificate(fhr.read()) + if compat_mode: + ca_cert = OpenSSL.crypto.load_certificate( + OpenSSL.crypto.FILETYPE_PEM, fhr.read() + ) + else: + ca_cert = cryptography.x509.load_pem_x509_certificate(fhr.read()) except OSError: return 'There is no CA named "{}"'.format(ca_name) except ValueError as e: @@ -1613,34 +1622,58 @@ def create_pkcs12(ca_name, CN, passphrase="", cacert_path=None, replace=False): try: with salt.utils.files.fopen(cert_path, "rb") as fhr: - cert = cryptography.x509.load_pem_x509_certificate(fhr.read()) + if compat_mode: + cert = OpenSSL.crypto.load_certificate( + OpenSSL.crypto.FILETYPE_PEM, fhr.read() + ) + else: + cert = cryptography.x509.load_pem_x509_certificate(fhr.read()) with salt.utils.files.fopen(priv_key_path, "rb") as fhr: - key = cryptography_serialization.load_pem_private_key( - fhr.read(), - password=None, - ) + if compat_mode: + key = OpenSSL.crypto.load_privatekey( + OpenSSL.crypto.FILETYPE_PEM, fhr.read() + ) + else: + key = cryptography_serialization.load_pem_private_key( + fhr.read(), + password=None, + ) except OSError: return 'There is no certificate that matches the CN "{}"'.format(CN) except ValueError as e: return f'Could not load certificate {cert_path}: {e}' - if passphrase: - encryption_algorithm = cryptography_serialization.BestAvailableEncryption( - salt.utils.stringutils.to_bytes(passphrase) - ) + if compat_mode: + pkcs12 = OpenSSL.crypto.PKCS12() + + pkcs12.set_certificate(cert) + pkcs12.set_ca_certificates([ca_cert]) + pkcs12.set_privatekey(key) + + with salt.utils.files.fopen( + "{}/{}/certs/{}.p12".format(cert_base_path(), ca_name, CN), "wb" + ) as ofile: + ofile.write( + pkcs12.export(passphrase=salt.utils.stringutils.to_bytes(passphrase)) + ) else: - encryption_algorithm = cryptography_serialization.NoEncryption() + if passphrase: + encryption_algorithm = cryptography_serialization.BestAvailableEncryption( + salt.utils.stringutils.to_bytes(passphrase) + ) + else: + encryption_algorithm = cryptography_serialization.NoEncryption() - pkcs12 = cryptography_pkcs12.serialize_key_and_certificates( - name=salt.utils.stringutils.to_bytes(CN), - key=key, - cert=cert, - cas=[ca_cert], - encryption_algorithm=encryption_algorithm, - ) + pkcs12 = cryptography_pkcs12.serialize_key_and_certificates( + name=salt.utils.stringutils.to_bytes(CN), + key=key, + cert=cert, + cas=[ca_cert], + encryption_algorithm=encryption_algorithm, + ) - with salt.utils.files.fopen(p12_path, "wb") as ofile: - ofile.write(pkcs12) + with salt.utils.files.fopen(p12_path, "wb") as ofile: + ofile.write(pkcs12) return 'Created PKCS#12 Certificate for "{0}": "{1}/{2}/certs/{0}.p12"'.format( CN, diff --git a/salt/modules/x509.py b/salt/modules/x509.py index 164541fc76..373e394856 100644 --- a/salt/modules/x509.py +++ b/salt/modules/x509.py @@ -32,16 +32,20 @@ import tempfile import salt.exceptions import salt.utils.data -import salt.utils.dictupdate import salt.utils.files import salt.utils.path import salt.utils.platform import salt.utils.stringutils import salt.utils.versions -import salt.utils.x509 as x509util from salt.state import STATE_INTERNAL_KEYWORDS as _STATE_INTERNAL_KEYWORDS from salt.utils.odict import OrderedDict +# Necessary for OSes with older cryptography module +COMPAT_MODE = sys.version_info < (3,12) +if not COMPAT_MODE: + import salt.utils.dictupdate + import salt.utils.x509 as x509util + try: import M2Crypto @@ -988,35 +992,113 @@ def create_crl( if revoked is None: revoked = [] + if COMPAT_MODE: + crl = OpenSSL.crypto.CRL() + for rev_item in revoked: + if "certificate" in rev_item: + rev_cert = read_certificate(rev_item["certificate"]) + rev_item["serial_number"] = rev_cert["Serial Number"] + rev_item["not_after"] = rev_cert["Not After"] - for rev_item in revoked: - if "reason" in rev_item: - salt.utils.dictupdate.set_dict_key_value( - rev_item, "extensions:CRLReason", rev_item["reason"] + serial_number = rev_item["serial_number"].replace(":", "") + # OpenSSL bindings requires this to be a non-unicode string + serial_number = salt.utils.stringutils.to_bytes(serial_number) + + if "not_after" in rev_item and not include_expired: + not_after = datetime.datetime.strptime( + rev_item["not_after"], "%Y-%m-%d %H:%M:%S" + ) + if datetime.datetime.now() > not_after: + continue + + if "revocation_date" not in rev_item: + rev_item["revocation_date"] = datetime.datetime.now().strftime( + "%Y-%m-%d %H:%M:%S" + ) + + rev_date = datetime.datetime.strptime( + rev_item["revocation_date"], "%Y-%m-%d %H:%M:%S" ) + rev_date = rev_date.strftime("%Y%m%d%H%M%SZ") + rev_date = salt.utils.stringutils.to_bytes(rev_date) - builder, private_key_obj = x509util.build_crl( - signing_private_key=signing_private_key, - signing_private_key_passphrase=signing_private_key_passphrase, - include_expired=include_expired, - revoked=revoked, - signing_cert=signing_cert, - days_valid=days_valid, - ) + rev = OpenSSL.crypto.Revoked() + rev.set_serial(salt.utils.stringutils.to_bytes(serial_number)) + rev.set_rev_date(salt.utils.stringutils.to_bytes(rev_date)) + + if "reason" in rev_item: + # Same here for OpenSSL bindings and non-unicode strings + reason = salt.utils.stringutils.to_bytes(rev_item["reason"]) + rev.set_reason(reason) + + crl.add_revoked(rev) + + signing_cert = _text_or_file(signing_cert) + cert = OpenSSL.crypto.load_certificate( + OpenSSL.crypto.FILETYPE_PEM, get_pem_entry(signing_cert, pem_type="CERTIFICATE") + ) + signing_private_key = _get_private_key_obj( + signing_private_key, passphrase=signing_private_key_passphrase + ).as_pem(cipher=None) + key = OpenSSL.crypto.load_privatekey( + OpenSSL.crypto.FILETYPE_PEM, get_pem_entry(signing_private_key) + ) + + export_kwargs = { + "cert": cert, + "key": key, + "type": OpenSSL.crypto.FILETYPE_PEM, + "days": days_valid, + } + if digest: + export_kwargs["digest"] = salt.utils.stringutils.to_bytes(digest) + else: + log.warning("No digest specified. The default md5 digest will be used.") + + try: + crltext = crl.export(**export_kwargs) + except (TypeError, ValueError): + log.warning( + "Error signing crl with specified digest. Are you using " + "pyopenssl 0.15 or newer? The default md5 digest will be used." + ) + export_kwargs.pop("digest", None) + crltext = crl.export(**export_kwargs) + + if text: + return crltext + + return write_pem(text=crltext, path=path, pem_type="X509 CRL") - if digest: - hashing_algorithm = x509util.get_hashing_algorithm(digest) else: - log.warning("No digest specified. The default md5 digest will be used.") - hashing_algorithm = x509util.get_hashing_algorithm("MD5") + for rev_item in revoked: + if "reason" in rev_item: + salt.utils.dictupdate.set_dict_key_value( + rev_item, "extensions:CRLReason", rev_item["reason"] + ) - crl = builder.sign(private_key_obj, algorithm=hashing_algorithm) - crl_bytes = crl.public_bytes(x509util.serialization.Encoding.PEM) + builder, private_key_obj = x509util.build_crl( + signing_private_key=signing_private_key, + signing_private_key_passphrase=signing_private_key_passphrase, + include_expired=include_expired, + revoked=revoked, + signing_cert=signing_cert, + days_valid=days_valid, + ) - if text: - return crl_bytes.decode() + if digest: + hashing_algorithm = x509util.get_hashing_algorithm(digest) + else: + log.warning("No digest specified. The default md5 digest will be used.") + hashing_algorithm = x509util.get_hashing_algorithm("MD5") - return write_pem(text=crl_bytes, path=path, pem_type="X509 CRL") + crl = builder.sign(private_key_obj, algorithm=hashing_algorithm) + crl_bytes = crl.public_bytes(x509util.serialization.Encoding.PEM) + + if text: + return crl_bytes.decode() + + return write_pem(text=crl_bytes, path=path, pem_type="X509 CRL") def sign_remote_certificate(argdic, **kwargs): -- 2.51.1
