From 2d78fa89a513b7a21403e259de41e21a2a475b27 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Sun, 3 Sep 2023 21:49:18 +0200 Subject: [PATCH] always implicitly require archive TAMs they must be there since the upgrade to borg 1.2.6 (or other borg versions that also have a fix for CVE-2023-36811). --- src/borg/archive.py | 9 ++++---- src/borg/cache.py | 2 +- src/borg/crypto/key.py | 30 +++++++-------------------- src/borg/testsuite/archiver/checks.py | 3 --- src/borg/testsuite/key.py | 3 +-- 5 files changed, 13 insertions(+), 34 deletions(-) diff --git a/src/borg/archive.py b/src/borg/archive.py index defbb28a0..3ce5e62c2 100644 --- a/src/borg/archive.py +++ b/src/borg/archive.py @@ -493,7 +493,7 @@ class Archive: self.name = name # overwritten later with name from archive metadata self.name_in_manifest = name # can differ from .name later (if borg check fixed duplicate archive names) self.comment = None - self.tam_verified = False + self.tam_verified = True self.numeric_ids = numeric_ids self.noatime = noatime self.noctime = noctime @@ -533,8 +533,7 @@ class Archive: def _load_meta(self, id): cdata = self.repository.get(id) _, data = self.repo_objs.parse(id, cdata) - # we do not require TAM for archives, otherwise we can not even borg list a repo with old archives. - archive, self.tam_verified, _ = self.key.unpack_and_verify_archive(data, force_tam_not_required=True) + archive, _ = self.key.unpack_and_verify_archive(data) metadata = ArchiveItem(internal_dict=archive) if metadata.version not in (1, 2): # legacy: still need to read v1 archives raise Exception("Unknown archive metadata version") @@ -1998,7 +1997,7 @@ class ArchiveChecker: # **after** doing the low-level checks and having a strong indication that we # are likely looking at an archive item here, also check the TAM authentication: try: - archive, verified, _ = self.key.unpack_and_verify_archive(data, force_tam_not_required=False) + archive, _ = self.key.unpack_and_verify_archive(data) except IntegrityError as integrity_error: # TAM issues - do not accept this archive! # either somebody is trying to attack us with a fake archive data or @@ -2269,7 +2268,7 @@ class ArchiveChecker: del self.manifest.archives[info.name] continue try: - archive, verified, salt = self.key.unpack_and_verify_archive(data, force_tam_not_required=False) + archive, salt = self.key.unpack_and_verify_archive(data) except IntegrityError as integrity_error: # looks like there is a TAM issue with this archive, this might be an attack! # when upgrading to borg 1.2.5, users are expected to TAM-authenticate all archives they diff --git a/src/borg/cache.py b/src/borg/cache.py index fc9fd1851..1f9e77521 100644 --- a/src/borg/cache.py +++ b/src/borg/cache.py @@ -755,7 +755,7 @@ class LocalCache(CacheStatsMixin): nonlocal processed_item_metadata_chunks csize, data = decrypted_repository.get(archive_id) chunk_idx.add(archive_id, 1, len(data)) - archive, verified, _ = self.key.unpack_and_verify_archive(data, force_tam_not_required=True) + archive, _ = self.key.unpack_and_verify_archive(data) archive = ArchiveItem(internal_dict=archive) if archive.version not in (1, 2): # legacy raise Exception("Unknown archive metadata version") diff --git a/src/borg/crypto/key.py b/src/borg/crypto/key.py index d6d6b32e5..ef9f86efa 100644 --- a/src/borg/crypto/key.py +++ b/src/borg/crypto/key.py @@ -15,7 +15,7 @@ import argon2.low_level from ..constants import * # NOQA from ..helpers import StableDict from ..helpers import Error, IntegrityError -from ..helpers import get_keys_dir, get_security_dir +from ..helpers import get_keys_dir from ..helpers import get_limited_unpacker from ..helpers import bin_to_hex from ..helpers.passphrase import Passphrase, PasswordRetriesExceeded, PassphraseWrong @@ -276,37 +276,21 @@ class KeyBase: logger.debug("TAM-verified manifest") return unpacked - def unpack_and_verify_archive(self, data, force_tam_not_required=False): - """Unpack msgpacked *data* and return (object, did_verify).""" - tam_required = self.tam_required - if force_tam_not_required and tam_required: - # for a long time, borg only checked manifest for "tam_required" and - # people might have archives without TAM, so don't be too annoyingly loud here: - logger.debug("Archive authentication DISABLED.") - tam_required = False + def unpack_and_verify_archive(self, data): + """Unpack msgpacked *data* and return (object, salt).""" data = bytearray(data) unpacker = get_limited_unpacker("archive") unpacker.feed(data) unpacked = unpacker.unpack() if "tam" not in unpacked: - if tam_required: - archive_name = unpacked.get("name", "") - raise ArchiveTAMRequiredError(archive_name) - else: - logger.debug("Archive TAM not found and not required") - return unpacked, False, None + archive_name = unpacked.get("name", "") + raise ArchiveTAMRequiredError(archive_name) tam = unpacked.pop("tam", None) if not isinstance(tam, dict): raise ArchiveTAMInvalid() tam_type = tam.get("type", "") if tam_type != "HKDF_HMAC_SHA512": - if tam_required: - raise TAMUnsupportedSuiteError(repr(tam_type)) - else: - logger.debug( - "Ignoring archive TAM made with unsupported suite, since TAM is not required: %r", tam_type - ) - return unpacked, False, None + raise TAMUnsupportedSuiteError(repr(tam_type)) tam_hmac = tam.get("hmac") tam_salt = tam.get("salt") if not isinstance(tam_salt, (bytes, str)) or not isinstance(tam_hmac, (bytes, str)): @@ -320,7 +304,7 @@ class KeyBase: if not hmac.compare_digest(calculated_hmac, tam_hmac): raise ArchiveTAMInvalid() logger.debug("TAM-verified archive") - return unpacked, True, tam_salt + return unpacked, tam_salt class PlaintextKey(KeyBase): diff --git a/src/borg/testsuite/archiver/checks.py b/src/borg/testsuite/archiver/checks.py index 766ac8602..bb8ca65e9 100644 --- a/src/borg/testsuite/archiver/checks.py +++ b/src/borg/testsuite/archiver/checks.py @@ -425,9 +425,6 @@ def test_check_rebuild_refcounts(archiver): repository = Repository(archiver.repository_path, exclusive=True) with repository: write_archive_without_tam(repository, "archive_no_tam") - output = cmd(archiver, "rlist", "--format='{name} tam:{tam}{NL}'") - assert "archive_tam tam:verified" in output # good - assert "archive_no_tam tam:none" in output # could be borg < 1.0.9 archive or fake cmd(archiver, "check", "--repair") output = cmd(archiver, "rlist", "--format='{name} tam:{tam}{NL}'") assert "archive_tam tam:verified" in output # TAM-verified archive still there diff --git a/src/borg/testsuite/key.py b/src/borg/testsuite/key.py index a8fd37681..749c792e4 100644 --- a/src/borg/testsuite/key.py +++ b/src/borg/testsuite/key.py @@ -352,8 +352,7 @@ class TestTAM: unpacked = msgpack.unpackb(blob) assert unpacked["tam"]["type"] == "HKDF_HMAC_SHA512" - unpacked, verified, _ = key.unpack_and_verify_archive(blob) - assert verified + unpacked, _ = key.unpack_and_verify_archive(blob) assert unpacked["foo"] == "bar" assert "tam" not in unpacked