|
@@ -136,16 +136,6 @@ def key_factory(repository, manifest_chunk, *, ro_cls=RepoObj):
|
|
return identify_key(manifest_data).detect(repository, manifest_data)
|
|
return identify_key(manifest_data).detect(repository, manifest_data)
|
|
|
|
|
|
|
|
|
|
-def tam_required_file(repository):
|
|
|
|
- security_dir = get_security_dir(bin_to_hex(repository.id), legacy=(repository.version == 1))
|
|
|
|
- return os.path.join(security_dir, "tam_required")
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-def tam_required(repository):
|
|
|
|
- file = tam_required_file(repository)
|
|
|
|
- return os.path.isfile(file)
|
|
|
|
-
|
|
|
|
-
|
|
|
|
def uses_same_chunker_secret(other_key, key):
|
|
def uses_same_chunker_secret(other_key, key):
|
|
"""is the chunker secret the same?"""
|
|
"""is the chunker secret the same?"""
|
|
# avoid breaking the deduplication by a different chunker secret
|
|
# avoid breaking the deduplication by a different chunker secret
|
|
@@ -211,7 +201,6 @@ class KeyBase:
|
|
self.TYPE_STR = bytes([self.TYPE])
|
|
self.TYPE_STR = bytes([self.TYPE])
|
|
self.repository = repository
|
|
self.repository = repository
|
|
self.target = None # key location file path / repo obj
|
|
self.target = None # key location file path / repo obj
|
|
- self.tam_required = True
|
|
|
|
self.copy_crypt_key = False
|
|
self.copy_crypt_key = False
|
|
|
|
|
|
def id_hash(self, data):
|
|
def id_hash(self, data):
|
|
@@ -253,39 +242,25 @@ class KeyBase:
|
|
tam["hmac"] = hmac.digest(tam_key, packed, "sha512")
|
|
tam["hmac"] = hmac.digest(tam_key, packed, "sha512")
|
|
return msgpack.packb(metadata_dict)
|
|
return msgpack.packb(metadata_dict)
|
|
|
|
|
|
- def unpack_and_verify_manifest(self, data, force_tam_not_required=False):
|
|
|
|
- """Unpack msgpacked *data* and return (object, did_verify)."""
|
|
|
|
|
|
+ def unpack_and_verify_manifest(self, data):
|
|
|
|
+ """Unpack msgpacked *data* and return manifest."""
|
|
if data.startswith(b"\xc1" * 4):
|
|
if data.startswith(b"\xc1" * 4):
|
|
# This is a manifest from the future, we can't read it.
|
|
# This is a manifest from the future, we can't read it.
|
|
raise UnsupportedManifestError()
|
|
raise UnsupportedManifestError()
|
|
- tam_required = self.tam_required
|
|
|
|
- if force_tam_not_required and tam_required:
|
|
|
|
- logger.warning("Manifest authentication DISABLED.")
|
|
|
|
- tam_required = False
|
|
|
|
data = bytearray(data)
|
|
data = bytearray(data)
|
|
unpacker = get_limited_unpacker("manifest")
|
|
unpacker = get_limited_unpacker("manifest")
|
|
unpacker.feed(data)
|
|
unpacker.feed(data)
|
|
unpacked = unpacker.unpack()
|
|
unpacked = unpacker.unpack()
|
|
if AUTHENTICATED_NO_KEY:
|
|
if AUTHENTICATED_NO_KEY:
|
|
- return unpacked, True # True is a lie.
|
|
|
|
|
|
+ return unpacked
|
|
if "tam" not in unpacked:
|
|
if "tam" not in unpacked:
|
|
- if tam_required:
|
|
|
|
- raise TAMRequiredError(self.repository._location.canonical_path())
|
|
|
|
- else:
|
|
|
|
- logger.debug("Manifest TAM not found and not required")
|
|
|
|
- return unpacked, False
|
|
|
|
|
|
+ raise TAMRequiredError(self.repository._location.canonical_path())
|
|
tam = unpacked.pop("tam", None)
|
|
tam = unpacked.pop("tam", None)
|
|
if not isinstance(tam, dict):
|
|
if not isinstance(tam, dict):
|
|
raise TAMInvalid()
|
|
raise TAMInvalid()
|
|
tam_type = tam.get("type", "<none>")
|
|
tam_type = tam.get("type", "<none>")
|
|
if tam_type != "HKDF_HMAC_SHA512":
|
|
if tam_type != "HKDF_HMAC_SHA512":
|
|
- if tam_required:
|
|
|
|
- raise TAMUnsupportedSuiteError(repr(tam_type))
|
|
|
|
- else:
|
|
|
|
- logger.debug(
|
|
|
|
- "Ignoring manifest TAM made with unsupported suite, since TAM is not required: %r", tam_type
|
|
|
|
- )
|
|
|
|
- return unpacked, False
|
|
|
|
|
|
+ raise TAMUnsupportedSuiteError(repr(tam_type))
|
|
tam_hmac = tam.get("hmac")
|
|
tam_hmac = tam.get("hmac")
|
|
tam_salt = tam.get("salt")
|
|
tam_salt = tam.get("salt")
|
|
if not isinstance(tam_salt, (bytes, str)) or not isinstance(tam_hmac, (bytes, str)):
|
|
if not isinstance(tam_salt, (bytes, str)) or not isinstance(tam_hmac, (bytes, str)):
|
|
@@ -299,7 +274,7 @@ class KeyBase:
|
|
if not hmac.compare_digest(calculated_hmac, tam_hmac):
|
|
if not hmac.compare_digest(calculated_hmac, tam_hmac):
|
|
raise TAMInvalid()
|
|
raise TAMInvalid()
|
|
logger.debug("TAM-verified manifest")
|
|
logger.debug("TAM-verified manifest")
|
|
- return unpacked, True
|
|
|
|
|
|
+ return unpacked
|
|
|
|
|
|
def unpack_and_verify_archive(self, data, force_tam_not_required=False):
|
|
def unpack_and_verify_archive(self, data, force_tam_not_required=False):
|
|
"""Unpack msgpacked *data* and return (object, did_verify)."""
|
|
"""Unpack msgpacked *data* and return (object, did_verify)."""
|
|
@@ -357,10 +332,6 @@ class PlaintextKey(KeyBase):
|
|
chunk_seed = 0
|
|
chunk_seed = 0
|
|
logically_encrypted = False
|
|
logically_encrypted = False
|
|
|
|
|
|
- def __init__(self, repository):
|
|
|
|
- super().__init__(repository)
|
|
|
|
- self.tam_required = False
|
|
|
|
-
|
|
|
|
@classmethod
|
|
@classmethod
|
|
def create(cls, repository, args, **kw):
|
|
def create(cls, repository, args, **kw):
|
|
logger.info('Encryption NOT enabled.\nUse the "--encryption=repokey|keyfile" to enable encryption.')
|
|
logger.info('Encryption NOT enabled.\nUse the "--encryption=repokey|keyfile" to enable encryption.')
|
|
@@ -526,7 +497,6 @@ class FlexiKey:
|
|
self.crypt_key = key.crypt_key
|
|
self.crypt_key = key.crypt_key
|
|
self.id_key = key.id_key
|
|
self.id_key = key.id_key
|
|
self.chunk_seed = key.chunk_seed
|
|
self.chunk_seed = key.chunk_seed
|
|
- self.tam_required = key.get("tam_required", tam_required(self.repository))
|
|
|
|
return True
|
|
return True
|
|
return False
|
|
return False
|
|
|
|
|
|
@@ -639,7 +609,6 @@ class FlexiKey:
|
|
crypt_key=self.crypt_key,
|
|
crypt_key=self.crypt_key,
|
|
id_key=self.id_key,
|
|
id_key=self.id_key,
|
|
chunk_seed=self.chunk_seed,
|
|
chunk_seed=self.chunk_seed,
|
|
- tam_required=self.tam_required,
|
|
|
|
)
|
|
)
|
|
data = self.encrypt_key_file(msgpack.packb(key.as_dict()), passphrase, algorithm)
|
|
data = self.encrypt_key_file(msgpack.packb(key.as_dict()), passphrase, algorithm)
|
|
key_data = "\n".join(textwrap.wrap(b2a_base64(data).decode("ascii")))
|
|
key_data = "\n".join(textwrap.wrap(b2a_base64(data).decode("ascii")))
|