From 76f67a2048d62aa4ee2158e7b80b1a44f7022b73 Mon Sep 17 00:00:00 2001 From: Florian Bach Date: Thu, 28 Jul 2022 18:07:52 +0200 Subject: [PATCH] Temporarily switch to oscrypto fork for OpenSSL 3 support. The latest version of oscrypto does not yet support OpenSSL 3, which is used in Ubuntu 22.04, Fedora 36 and a bunch of other newer Linux distributions. When https://github.com/wbond/oscrypto/pull/61 is merged and included in a new release, this change will be reverted. --- .github/workflows/main.yml | 29 ++- bundle_calibre_plugin.sh | 2 +- calibre-plugin/__init__.py | 34 +--- .../_libcrypto_replacement_file_bugfix.py | 179 ------------------ package_modules.sh | 5 +- 5 files changed, 36 insertions(+), 213 deletions(-) delete mode 100644 calibre-plugin/_libcrypto_replacement_file_bugfix.py diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d3ad9ee..b8d41fc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -49,7 +49,7 @@ jobs: run: | cd tests && PYTHONWARNINGS=ignore python2 ./main.py && cd .. - test-ubuntu-2204: + test-ubuntu-2204-oscrypto: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 @@ -73,6 +73,33 @@ jobs: run: | cd tests && PYTHONWARNINGS=ignore python2 ./main.py && cd .. + test-ubuntu-2204-oscrypto-fork: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v2 + + - name: Install dependencies + run: | + # Require cryptography >= 3.1 because in 3.0 and below, the backend param in load_key_and_certificates was still required. + # Installing a forked version of oscrypto to fix OpenSSL 3 issues + pip3 install freezegun lxml pycryptodome rsa "cryptography>=3.1" + pip3 install https://github.com/Leseratte10/acsm-calibre-plugin/releases/download/config/oscrypto_1.3.0_fork_fe39273cc5020.zip + # Install Python2 stuff + curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py + sudo apt install python2 + python2 get-pip.py + pip2 install freezegun mock lxml pycryptodome "rsa<=4.3" cryptography==3.1 + pip2 install https://github.com/Leseratte10/acsm-calibre-plugin/releases/download/config/oscrypto_1.3.0_fork_fe39273cc5020.zip + + - name: Run tests (Python 3) + run: | + cd tests && python3 ./main.py && cd .. + + - name: Run tests (Python 2) + run: | + cd tests && PYTHONWARNINGS=ignore python2 ./main.py && cd .. + + test-windows: runs-on: windows-2022 steps: diff --git a/bundle_calibre_plugin.sh b/bundle_calibre_plugin.sh index bf1aae1..c905cdb 100755 --- a/bundle_calibre_plugin.sh +++ b/bundle_calibre_plugin.sh @@ -37,7 +37,7 @@ rm -r __pycache__ rm *.pyc # Set module ID. This needs to be changed if any of the module ZIPs change. -echo -n "2022-06-15-01" > module_id.txt +echo -n "2022-07-28-01" > module_id.txt # Copy LICENSE and README.md so it'll be included in the ZIP. cp ../LICENSE LICENSE diff --git a/calibre-plugin/__init__.py b/calibre-plugin/__init__.py index f4ec086..9fa25bc 100644 --- a/calibre-plugin/__init__.py +++ b/calibre-plugin/__init__.py @@ -40,7 +40,8 @@ # add a ton of testing code, try to prevent AV false-positives, # experimental support for Python2 / Calibre < 5, # fix broken URLs with missing protocol, fix loan data for loans without device ID, -# fix nonce calculation yet again. +# fix nonce calculation yet again, +# update python-oscrypto to unofficial fork to fix OpenSSL 3 support. PLUGIN_NAME = "DeACSM" PLUGIN_VERSION_TUPLE = (0, 0, 15) @@ -159,36 +160,7 @@ class DeACSM(FileTypePlugin): except: print("{0} v{1}: Exception when copying needed library files".format(PLUGIN_NAME, PLUGIN_VERSION)) traceback.print_exc() - pass - - - # TEMPORARY - # oscrypto still doesn't support Ubuntu 22.04 - # add a hacky bugfix - # once oscrypto supports 22.04, this can be removed. - - ts_dict = self.load_resources( ["module_id.txt"] ) - id_plugin = ts_dict["module_id.txt"].decode("latin-1").split('\n')[0].strip() - - if islinux: - try: - print("{0} v{1}: Patching oscrypto for OpenSSL3 support".format(PLUGIN_NAME, PLUGIN_VERSION)) - res_dict = self.load_resources( ["_libcrypto_replacement_file_bugfix.py"] ) - bugfix_file = res_dict["_libcrypto_replacement_file_bugfix.py"] - dest_path = os.path.join(rand_path, "oscrypto", "oscrypto", "_openssl", "_libcrypto.py") - backup_path = os.path.join(rand_path, "oscrypto", "oscrypto", "_openssl", "_libcrypto.py.bak") - - shutil.copyfile(dest_path, backup_path) - f = open(dest_path, "wb") - f.write(bugfix_file) - f.close() - print("{0} v{1}: Patch done".format(PLUGIN_NAME, PLUGIN_VERSION)) - except: - print("{0} v{1}: Error while patching oscrypto".format(PLUGIN_NAME, PLUGIN_VERSION)) - traceback.print_exc() - - # TEMPORARY END - + pass if islinux: diff --git a/calibre-plugin/_libcrypto_replacement_file_bugfix.py b/calibre-plugin/_libcrypto_replacement_file_bugfix.py deleted file mode 100644 index 1aed454..0000000 --- a/calibre-plugin/_libcrypto_replacement_file_bugfix.py +++ /dev/null @@ -1,179 +0,0 @@ -# coding: utf-8 -# This file is part of the oscrypto project: -# https://github.com/wbond/oscrypto -# It's been patched to fix OpenSSL3 issues: -# https://github.com/wbond/oscrypto/pull/61 -# -# As soon as this PR is merged and a new version of oscrypto is released, -# this temporary hack will be removed from the ACSM Input plugin. -# -# oscrypto is under the MIT license: -# Copyright (c) 2015-2022 Will Bond -# -# Permission is hereby granted, free of charge, to any person obtaining a copy of -# this software and associated documentation files (the "Software"), to deal in -# the Software without restriction, including without limitation the rights to -# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -# of the Software, and to permit persons to whom the Software is furnished to do -# so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from __future__ import unicode_literals, division, absolute_import, print_function - -from .. import ffi -from .._ffi import buffer_from_bytes, byte_string_from_buffer, null -from .._types import str_cls - -if ffi() == 'cffi': - from ._libcrypto_cffi import ( - libcrypto, - version as libcrypto_version, - version_info as libcrypto_version_info - ) -else: - from ._libcrypto_ctypes import ( - libcrypto, - version as libcrypto_version, - version_info as libcrypto_version_info - ) - - -__all__ = [ - 'handle_openssl_error', - 'libcrypto', - 'libcrypto_legacy_support', - 'libcrypto_version', - 'libcrypto_version_info', - 'LibcryptoConst', - 'peek_openssl_error', -] - - -_encoding = 'utf-8' -_fallback_encodings = ['utf-8', 'cp1252'] - - -if libcrypto_version_info < (1, 1): - libcrypto.ERR_load_crypto_strings() -libcrypto.OPENSSL_config(null()) - - -# This enables legacy algorithms in OpenSSL 3.0, such as RC2, etc -# which are used by various tests and some old protocols and things -# like PKCS12 -libcrypto_legacy_support = True -if libcrypto_version_info >= (3, ): - libcrypto.OSSL_PROVIDER_load(null(), "legacy".encode("ascii")) - libcrypto.OSSL_PROVIDER_load(null(), "default".encode("ascii")) - - if libcrypto.OSSL_PROVIDER_available(null(), "legacy".encode("ascii")) == 0: - libcrypto_legacy_support = False - - -def _try_decode(value): - - try: - return str_cls(value, _encoding) - - # If the "correct" encoding did not work, try some defaults, and then just - # obliterate characters that we can't seen to decode properly - except (UnicodeDecodeError): - for encoding in _fallback_encodings: - try: - return str_cls(value, encoding, errors='strict') - except (UnicodeDecodeError): - pass - - return str_cls(value, errors='replace') - - -def handle_openssl_error(result, exception_class=None): - """ - Checks if an error occurred, and if so throws an OSError containing the - last OpenSSL error message - - :param result: - An integer result code - 1 or greater indicates success - - :param exception_class: - The exception class to use for the exception if an error occurred - - :raises: - OSError - when an OpenSSL error occurs - """ - - if result > 0: - return - - if exception_class is None: - exception_class = OSError - - error_num = libcrypto.ERR_get_error() - buffer = buffer_from_bytes(120) - libcrypto.ERR_error_string(error_num, buffer) - - # Since we are dealing with a string, it is NULL terminated - error_string = byte_string_from_buffer(buffer) - - raise exception_class(_try_decode(error_string)) - - -def peek_openssl_error(): - """ - Peeks into the error stack and pulls out the lib, func and reason - - :return: - A three-element tuple of integers (lib, func, reason) - """ - - error = libcrypto.ERR_peek_error() - if libcrypto_version_info < (3, 0): - lib = int((error >> 24) & 0xff) - func = int((error >> 12) & 0xfff) - reason = int(error & 0xfff) - else: - lib = int((error >> 23) & 0xff) - # OpenSSL 3.0 removed ERR_GET_FUNC() - func = 0 - reason = int(error & 0x7fffff) - - return (lib, func, reason) - - -class LibcryptoConst(): - EVP_CTRL_SET_RC2_KEY_BITS = 3 - - SSLEAY_VERSION = 0 - - RSA_PKCS1_PADDING = 1 - RSA_NO_PADDING = 3 - RSA_PKCS1_OAEP_PADDING = 4 - - # OpenSSL 0.9.x - EVP_MD_CTX_FLAG_PSS_MDLEN = -1 - - # OpenSSL 1.x.x - EVP_PKEY_CTRL_RSA_PADDING = 0x1001 - RSA_PKCS1_PSS_PADDING = 6 - EVP_PKEY_CTRL_RSA_PSS_SALTLEN = 0x1002 - EVP_PKEY_RSA = 6 - EVP_PKEY_OP_SIGN = 1 << 3 - EVP_PKEY_OP_VERIFY = 1 << 4 - - NID_X9_62_prime256v1 = 415 - NID_secp384r1 = 715 - NID_secp521r1 = 716 - - OPENSSL_EC_NAMED_CURVE = 1 - - DH_GENERATOR_2 = 2 diff --git a/package_modules.sh b/package_modules.sh index 330d4fc..b935e9f 100755 --- a/package_modules.sh +++ b/package_modules.sh @@ -2,8 +2,11 @@ pushd calibre-plugin +# As the latest oscrypto release (1.3.0) does not yet support OpenSSL3, we'll have to download a forked version ... +# See https://github.com/wbond/oscrypto/pull/61 for more information. + wget https://github.com/Leseratte10/acsm-calibre-plugin/releases/download/config/asn1crypto_1.5.1.zip -O asn1crypto.zip -wget https://github.com/Leseratte10/acsm-calibre-plugin/releases/download/config/oscrypto_1.3.0.zip -O oscrypto.zip +wget https://github.com/Leseratte10/acsm-calibre-plugin/releases/download/config/oscrypto_1.3.0_fork_fe39273cc5020.zip -O oscrypto.zip popd