From 005662a8fe165c48ab6542ea4597e4b964ab95d9 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Sat, 24 Jun 2023 01:06:16 +0200 Subject: [PATCH] upgrade --archives-tam: make sure all archives are TAM authenticated borg check (rebuild_manifest and rebuild_refcounts) drops archives without TAM, so let's just always add the TAM. for unencrypted repos (encryption=none) the TAM is insecure, but without encryption and authentication, there is no expectation of security anyway. --- src/borg/archiver.py | 53 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/src/borg/archiver.py b/src/borg/archiver.py index 06a90b7ec..98577e5d3 100644 --- a/src/borg/archiver.py +++ b/src/borg/archiver.py @@ -72,10 +72,11 @@ try: from .helpers import umount from .helpers import msgpack, msgpack_fallback from .helpers import uid2user, gid2group + from .helpers import safe_decode from .nanorst import rst_to_terminal from .patterns import ArgparsePatternAction, ArgparseExcludeFileAction, ArgparsePatternFileAction, parse_exclude_pattern from .patterns import PatternMatcher - from .item import Item + from .item import Item, ArchiveItem from .platform import get_flags, get_process_id, SyncFile from .remote import RepositoryServer, RemoteRepository, cache_if_remote from .repository import Repository, LIST_SCAN_LIMIT, TAG_PUT, TAG_DELETE, TAG_COMMIT @@ -1711,10 +1712,34 @@ class Archiver: DASHES, logger=logging.getLogger('borg.output.stats')) return self.exit_code - @with_repository(fake=('tam', 'disable_tam'), invert_fake=True, manifest=False, exclusive=True) + @with_repository(fake=('tam', 'disable_tam', 'archives_tam'), invert_fake=True, manifest=False, exclusive=True) def do_upgrade(self, args, repository, manifest=None, key=None): """upgrade a repository from a previous version""" - if args.tam: + if args.archives_tam: + manifest, key = Manifest.load(repository, (Manifest.Operation.CHECK,), force_tam_not_required=args.force) + with Cache(repository, key, manifest) as cache: + stats = Statistics() + for info in manifest.archives.list(sort_by=['ts']): + archive_id = info.id + archive_formatted = format_archive(info) + cdata = repository.get(archive_id) + data = key.decrypt(archive_id, cdata) + archive, verified = key.unpack_and_verify_archive(data, force_tam_not_required=True) + if not verified: # we do not have an archive TAM yet -> add TAM now! + archive = ArchiveItem(internal_dict=archive) + archive.cmdline = [safe_decode(arg) for arg in archive.cmdline] + data = key.pack_and_authenticate_metadata(archive.as_dict(), context=b'archive') + new_archive_id = key.id_hash(data) + cache.add_chunk(new_archive_id, data, stats) + cache.chunk_decref(archive_id, stats) + manifest.archives[info.name] = (new_archive_id, info.ts) + print("Added archive TAM: %s -> [%s]" % (archive_formatted, bin_to_hex(new_archive_id))) + else: + print("Archive TAM present: %s" % archive_formatted) + manifest.write() + repository.commit(compact=False) + cache.commit() + elif args.tam: manifest, key = Manifest.load(repository, (Manifest.Operation.CHECK,), force_tam_not_required=args.force) if not hasattr(key, 'change_passphrase'): @@ -1722,10 +1747,9 @@ class Archiver: return EXIT_ERROR if not manifest.tam_verified or not manifest.config.get(b'tam_required', False): - # The standard archive listing doesn't include the archive ID like in borg 1.1.x print('Manifest contents:') for archive_info in manifest.archives.list(sort_by=['ts']): - print(format_archive(archive_info), '[%s]' % bin_to_hex(archive_info.id)) + print(format_archive(archive_info)) manifest.config[b'tam_required'] = True manifest.write() repository.commit() @@ -4103,6 +4127,23 @@ class Archiver: Borg 1.x.y upgrades +++++++++++++++++++ + Archive TAM authentication: + + Use ``borg upgrade --archives-tam REPO`` to add archive TAMs to all + archives that are not TAM authenticated yet. + This is a convenient method to just trust all archives present - if + an archive does not have TAM authentication yet, a TAM will be added. + Archives created by old borg versions < 1.0.9 do not have TAMs. + Archives created by newer borg version should have TAMs already. + If you have a high risk environment, you should not just run this, + but first verify that the archives are authentic and not malicious + (== have good content, have a good timestamp). + Borg 1.2.5+ needs all archives to be TAM authenticated for safety reasons. + + This upgrade needs to be done once per repository. + + Manifest TAM authentication: + Use ``borg upgrade --tam REPO`` to require manifest authentication introduced with Borg 1.0.9 to address security issues. This means that modifying the repository after doing this with a version prior @@ -4183,6 +4224,8 @@ class Archiver: help='Enable manifest authentication (in key and cache) (Borg 1.0.9 and later).') subparser.add_argument('--disable-tam', dest='disable_tam', action='store_true', help='Disable manifest authentication (in key and cache).') + subparser.add_argument('--archives-tam', dest='archives_tam', action='store_true', + help='add TAM authentication for all archives.') subparser.add_argument('location', metavar='REPOSITORY', nargs='?', default='', type=location_validator(archive=False), help='path to the repository to be upgraded')