From c592b202623f534930172670f67b793646b81b14 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 14 Apr 2022 12:14:15 +0200 Subject: [PATCH 1/2] use openssl on openbsd, fixes #6474 --- Vagrantfile | 1 + docs/installation.rst | 2 +- setup.py | 8 ++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Vagrantfile b/Vagrantfile index eea43d8c2d..359ae6d629 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -78,6 +78,7 @@ def packages_openbsd pkg_add lz4 pkg_add zstd pkg_add git # no fakeroot + pkg_add openssl%1.1 pkg_add py3-pip pkg_add py3-virtualenv EOF diff --git a/docs/installation.rst b/docs/installation.rst index 2d01e7a879..6c778d7831 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -162,7 +162,7 @@ following dependencies first: * `Python 3`_ >= 3.9.0, plus development headers. * Libraries (library plus development headers): - - OpenSSL_ >= 1.1.1 + - OpenSSL_ >= 1.1.1 (LibreSSL will not work) - libacl_ (which depends on libattr_) - liblz4_ >= 1.7.0 (r129) - libzstd_ >= 1.3.0 diff --git a/setup.py b/setup.py index 9b1e884fd5..083b50f1de 100644 --- a/setup.py +++ b/setup.py @@ -23,6 +23,7 @@ import setup_docs is_win32 = sys.platform.startswith('win32') +is_openbsd = sys.platform.startswith('openbsd') # Number of threads to use for cythonize, not used on windows cpu_threads = multiprocessing.cpu_count() if multiprocessing and multiprocessing.get_start_method() != 'spawn' else None @@ -156,9 +157,15 @@ def lib_ext_kwargs(pc, prefix_env_var, lib_name, lib_pkg_name, pc_version, lib_s f"or ensure {lib_pkg_name}.pc is in PKG_CONFIG_PATH." ) + crypto_ldflags = [] if is_win32: crypto_ext_lib = lib_ext_kwargs( pc, 'BORG_OPENSSL_PREFIX', 'libcrypto', 'libcrypto', '>=1.1.1', lib_subdir='') + elif is_openbsd: + # use openssl (not libressl) because we need AES-OCB and CHACHA20-POLY1305 via EVP api + crypto_ext_lib = lib_ext_kwargs( + pc, 'BORG_OPENSSL_PREFIX', 'crypto', 'libecrypto11', '>=1.1.1') + crypto_ldflags += ['-Wl,-rpath=/usr/local/lib/eopenssl11'] else: crypto_ext_lib = lib_ext_kwargs( pc, 'BORG_OPENSSL_PREFIX', 'crypto', 'libcrypto', '>=1.1.1') @@ -167,6 +174,7 @@ def lib_ext_kwargs(pc, prefix_env_var, lib_name, lib_pkg_name, pc_version, lib_s dict(sources=[crypto_ll_source, crypto_helpers]), crypto_ext_lib, dict(extra_compile_args=cflags), + dict(extra_link_args=crypto_ldflags), ) compress_ext_kwargs = members_appended( From be9e7d37c250426d26f545172ecf04b07826f3d4 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Thu, 14 Apr 2022 19:16:25 +0200 Subject: [PATCH 2/2] remove libressl support currently it does not have what we need, so we can simplify our code. --- setup.py | 3 +-- src/borg/archiver.py | 12 ++++------ src/borg/crypto/_crypto_helpers.c | 14 ------------ src/borg/crypto/_crypto_helpers.h | 13 ----------- src/borg/crypto/low_level.pyx | 18 ++++----------- src/borg/testsuite/crypto.py | 37 ++++++++++++------------------- 6 files changed, 23 insertions(+), 74 deletions(-) delete mode 100644 src/borg/crypto/_crypto_helpers.c delete mode 100644 src/borg/crypto/_crypto_helpers.h diff --git a/setup.py b/setup.py index 083b50f1de..2d91a6a476 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,6 @@ compress_source = 'src/borg/compress.pyx' crypto_ll_source = 'src/borg/crypto/low_level.pyx' -crypto_helpers = 'src/borg/crypto/_crypto_helpers.c' chunker_source = 'src/borg/chunker.pyx' hashindex_source = 'src/borg/hashindex.pyx' item_source = 'src/borg/item.pyx' @@ -171,7 +170,7 @@ def lib_ext_kwargs(pc, prefix_env_var, lib_name, lib_pkg_name, pc_version, lib_s pc, 'BORG_OPENSSL_PREFIX', 'crypto', 'libcrypto', '>=1.1.1') crypto_ext_kwargs = members_appended( - dict(sources=[crypto_ll_source, crypto_helpers]), + dict(sources=[crypto_ll_source]), crypto_ext_lib, dict(extra_compile_args=cflags), dict(extra_link_args=crypto_ldflags), diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 971226f864..bf7f9d70ac 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -602,7 +602,6 @@ def chunkit(chunker_name, *args, **kwargs): from borg.crypto.low_level import AES256_CTR_BLAKE2b, AES256_CTR_HMAC_SHA256 from borg.crypto.low_level import AES256_OCB, CHACHA20_POLY1305 - from borg.crypto.low_level import is_libressl print("Encryption =====================================================") size = "1GB" @@ -611,14 +610,11 @@ def chunkit(chunker_name, *args, **kwargs): key_256, key_256, iv=key_128, header_len=1, aad_offset=1).encrypt(random_10M, header=b'X')), ("aes-256-ctr-blake2b", lambda: AES256_CTR_BLAKE2b( key_256*4, key_256, iv=key_128, header_len=1, aad_offset=1).encrypt(random_10M, header=b'X')), + ("aes-256-ocb", lambda: AES256_OCB( + key_256, iv=key_96, header_len=1, aad_offset=1).encrypt(random_10M, header=b'X')), + ("chacha20-poly1305", lambda: CHACHA20_POLY1305( + key_256, iv=key_96, header_len=1, aad_offset=1).encrypt(random_10M, header=b'X')), ] - if not is_libressl: - tests.extend([ - ("aes-256-ocb", lambda: AES256_OCB( - key_256, iv=key_96, header_len=1, aad_offset=1).encrypt(random_10M, header=b'X')), - ("chacha20-poly1305", lambda: CHACHA20_POLY1305( - key_256, iv=key_96, header_len=1, aad_offset=1).encrypt(random_10M, header=b'X')), - ]) for spec, func in tests: print(f"{spec:<24} {size:<10} {timeit(func, number=100):.3f}s") diff --git a/src/borg/crypto/_crypto_helpers.c b/src/borg/crypto/_crypto_helpers.c deleted file mode 100644 index 8a6460640d..0000000000 --- a/src/borg/crypto/_crypto_helpers.c +++ /dev/null @@ -1,14 +0,0 @@ -/* some helpers, so our code also works with LibreSSL */ - -#include -#include - -#if defined(LIBRESSL_VERSION_NUMBER) -const EVP_CIPHER *EVP_aes_256_ocb(void){ /* dummy, so that code compiles */ - return NULL; -} - -const EVP_CIPHER *EVP_chacha20_poly1305(void){ /* dummy, so that code compiles */ - return NULL; -} -#endif diff --git a/src/borg/crypto/_crypto_helpers.h b/src/borg/crypto/_crypto_helpers.h deleted file mode 100644 index 62517c1156..0000000000 --- a/src/borg/crypto/_crypto_helpers.h +++ /dev/null @@ -1,13 +0,0 @@ -/* some helpers, so our code also works with LibreSSL */ - -#include -#include - -#if defined(LIBRESSL_VERSION_NUMBER) -const EVP_CIPHER *EVP_aes_256_ocb(void); /* dummy, so that code compiles */ -const EVP_CIPHER *EVP_chacha20_poly1305(void); /* dummy, so that code compiles */ -#endif - -#if !defined(LIBRESSL_VERSION_NUMBER) -#define LIBRESSL_VERSION_NUMBER 0 -#endif diff --git a/src/borg/crypto/low_level.pyx b/src/borg/crypto/low_level.pyx index 5692fa23c9..c0818abc51 100644 --- a/src/borg/crypto/low_level.pyx +++ b/src/borg/crypto/low_level.pyx @@ -47,6 +47,8 @@ API_VERSION = '1.3_01' cdef extern from "openssl/crypto.h": int CRYPTO_memcmp(const void *a, const void *b, size_t len) +cdef extern from "openssl/opensslv.h": + long OPENSSL_VERSION_NUMBER cdef extern from "openssl/evp.h": ctypedef struct EVP_MD: @@ -92,16 +94,6 @@ cdef extern from "openssl/hmac.h": const unsigned char *data, int data_len, unsigned char *md, unsigned int *md_len) nogil -cdef extern from "_crypto_helpers.h": - long OPENSSL_VERSION_NUMBER - long LIBRESSL_VERSION_NUMBER - - const EVP_CIPHER *EVP_aes_256_ocb() # dummy - const EVP_CIPHER *EVP_chacha20_poly1305() # dummy - - -is_libressl = bool(LIBRESSL_VERSION_NUMBER) - import struct @@ -600,8 +592,7 @@ cdef class _AEAD_BASE: cdef class AES256_OCB(_AEAD_BASE): @classmethod def requirements_check(cls): - if is_libressl: - raise ValueError('AES OCB is not implemented by LibreSSL (yet?).') + pass def __init__(self, key, iv=None, header_len=0, aad_offset=0): self.requirements_check() @@ -613,8 +604,7 @@ cdef class AES256_OCB(_AEAD_BASE): cdef class CHACHA20_POLY1305(_AEAD_BASE): @classmethod def requirements_check(cls): - if is_libressl: - raise ValueError('CHACHA20-POLY1305 is not implemented by LibreSSL (yet?).') + pass def __init__(self, key, iv=None, header_len=0, aad_offset=0): self.requirements_check() diff --git a/src/borg/testsuite/crypto.py b/src/borg/testsuite/crypto.py index 7950f58f2b..570afbc1dc 100644 --- a/src/borg/testsuite/crypto.py +++ b/src/borg/testsuite/crypto.py @@ -3,8 +3,7 @@ import unittest -from ..crypto.low_level import AES256_CTR_HMAC_SHA256, AES256_OCB, CHACHA20_POLY1305, UNENCRYPTED, \ - IntegrityError, is_libressl +from ..crypto.low_level import AES256_CTR_HMAC_SHA256, AES256_OCB, CHACHA20_POLY1305, UNENCRYPTED, IntegrityError from ..crypto.low_level import bytes_to_long, bytes_to_int, long_to_bytes from ..crypto.low_level import hkdf_hmac_sha512 from ..crypto.low_level import AES, hmac_sha256 @@ -103,16 +102,13 @@ def test_AE(self): header = b'\x23' + iv_int.to_bytes(12, 'big') tests = [ # (ciphersuite class, exp_mac, exp_cdata) + (AES256_OCB, + b'b6909c23c9aaebd9abbe1ff42097652d', + b'877ce46d2f62dee54699cebc3ba41d9ab613f7c486778c1b3636664b1493', ), + (CHACHA20_POLY1305, + b'fd08594796e0706cde1e8b461e3e0555', + b'a093e4b0387526f085d3c40cca84a35230a5c0dd766453b77ba38bcff775', ) ] - if not is_libressl: - tests += [ - (AES256_OCB, - b'b6909c23c9aaebd9abbe1ff42097652d', - b'877ce46d2f62dee54699cebc3ba41d9ab613f7c486778c1b3636664b1493', ), - (CHACHA20_POLY1305, - b'fd08594796e0706cde1e8b461e3e0555', - b'a093e4b0387526f085d3c40cca84a35230a5c0dd766453b77ba38bcff775', ) - ] for cs_cls, exp_mac, exp_cdata in tests: # print(repr(cs_cls)) # encrypt/mac @@ -146,16 +142,13 @@ def test_AEAD(self): header = b'\x12\x34\x56' + iv_int.to_bytes(12, 'big') tests = [ # (ciphersuite class, exp_mac, exp_cdata) + (AES256_OCB, + b'f2748c412af1c7ead81863a18c2c1893', + b'877ce46d2f62dee54699cebc3ba41d9ab613f7c486778c1b3636664b1493', ), + (CHACHA20_POLY1305, + b'b7e7c9a79f2404e14f9aad156bf091dd', + b'a093e4b0387526f085d3c40cca84a35230a5c0dd766453b77ba38bcff775', ) ] - if not is_libressl: - tests += [ - (AES256_OCB, - b'f2748c412af1c7ead81863a18c2c1893', - b'877ce46d2f62dee54699cebc3ba41d9ab613f7c486778c1b3636664b1493', ), - (CHACHA20_POLY1305, - b'b7e7c9a79f2404e14f9aad156bf091dd', - b'a093e4b0387526f085d3c40cca84a35230a5c0dd766453b77ba38bcff775', ) - ] for cs_cls, exp_mac, exp_cdata in tests: # print(repr(cs_cls)) # encrypt/mac @@ -187,9 +180,7 @@ def test_AEAD_with_more_AAD(self): iv_int = 0 data = b'foo' * 10 header = b'\x12\x34' - tests = [] - if not is_libressl: - tests += [AES256_OCB, CHACHA20_POLY1305] + tests = [AES256_OCB, CHACHA20_POLY1305] for cs_cls in tests: # encrypt/mac cs = cs_cls(key, iv_int, header_len=len(header), aad_offset=0)