From a5801b9971fa3d38915a4293368f3dff3843c6e0 Mon Sep 17 00:00:00 2001 From: Thomas Waldmann Date: Tue, 27 Jun 2023 20:32:57 +0200 Subject: [PATCH] keyfile: improve key sanity check, fixes #7561 check key file structure, make sure the binary key is not way too short (or zero) length. if key file looks strange, emit warnings. --- src/borg/crypto/key.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/borg/crypto/key.py b/src/borg/crypto/key.py index 7a2e73886..7f309e605 100644 --- a/src/borg/crypto/key.py +++ b/src/borg/crypto/key.py @@ -1,3 +1,4 @@ +import binascii import configparser import getpass import hmac @@ -711,7 +712,29 @@ class KeyfileKey(ID_HMAC_SHA_256, KeyfileKeyBase): raise KeyfileInvalidError(self.repository._location.canonical_path(), filename) if fd.read(len(repo_id)) != repo_id: raise KeyfileMismatchError(self.repository._location.canonical_path(), filename) - return filename + # we get here if it really looks like a borg key for this repo, + # do some more checks that are close to how borg reads/parses the key. + with open(filename, 'r') as fd: + lines = fd.readlines() + if len(lines) < 2: + logger.warning(f"borg key sanity check: expected 2+ lines total. [{filename}]") + raise KeyfileInvalidError(self.repository._location.canonical_path(), filename) + if len(lines[0].rstrip()) > len(file_id) + len(repo_id): + logger.warning(f"borg key sanity check: key line 1 seems too long. [{filename}]") + raise KeyfileInvalidError(self.repository._location.canonical_path(), filename) + key_b64 = ''.join(lines[1:]) + try: + key = a2b_base64(key_b64) + except binascii.Error: + logger.warning(f"borg key sanity check: key line 2+ does not look like base64. [{filename}]") + raise KeyfileInvalidError(self.repository._location.canonical_path(), filename) + if len(key) < 20: + # this is in no way a precise check, usually we have about 400b key data. + logger.warning(f"borg key sanity check: binary encrypted key data from key line 2+ suspiciously short." + f" [{filename}]") + raise KeyfileInvalidError(self.repository._location.canonical_path(), filename) + # looks good! + return filename def find_key(self): keyfile = self._find_key_file_from_environment()