Hacky fix for OpenSSL 3

This commit is contained in:
Florian Bach 2022-05-14 18:56:33 +02:00
parent 03d8221cdc
commit d66913c1ae
3 changed files with 218 additions and 6 deletions

View file

@ -20,7 +20,7 @@ rm -r __pycache__
rm *.pyc
# Set module ID. This needs to be changed if any of the module ZIPs change.
echo -n "2022-05-01-01" > module_id.txt
echo -n "2022-05-14-02" > module_id.txt
# Copy LICENSE and README.md so it'll be included in the ZIP.
cp ../LICENSE LICENSE

View file

@ -160,6 +160,36 @@ class DeACSM(FileTypePlugin):
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
if islinux:
# Also extract EXE files needed for WINE ADE key extraction
names = [ "keyextract/decrypt_win32.exe", "keyextract/decrypt_win64.exe" ]
@ -189,7 +219,7 @@ class DeACSM(FileTypePlugin):
from libadobe import createDeviceKeyFile, update_account_path, sendHTTPRequest
from libadobeAccount import createDeviceFile, createUser, signIn, activateDevice
from libadobeFulfill import buildRights, fulfill, getDecryptedCert
from libadobeFulfill import buildRights, fulfill
import calibre_plugins.deacsm.prefs as prefs # type: ignore
@ -216,7 +246,6 @@ class DeACSM(FileTypePlugin):
deacsmprefs = prefs.DeACSM_Prefs()
from libadobe import get_activation_xml_path
from libadobeFulfill import getDecryptedCert
container = None
try:
@ -236,9 +265,13 @@ class DeACSM(FileTypePlugin):
print("ADE sanity check: pkcs12 missing")
return False
if getDecryptedCert() is None:
print("ADE sanity check: Can't decrypt pkcs12")
return False
try:
from libadobeFulfill import getDecryptedCert
if getDecryptedCert() is None:
print("ADE sanity check: Can't decrypt pkcs12")
return False
except:
print("Skipping decryption check")
return True
except:

View file

@ -0,0 +1,179 @@
# 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 <will@wbond.net>
#
# 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