summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gemato/exceptions.py2
-rw-r--r--gemato/verify.py11
-rw-r--r--tests/test_verify.py34
3 files changed, 43 insertions, 4 deletions
diff --git a/gemato/exceptions.py b/gemato/exceptions.py
index ad9002a..71283ea 100644
--- a/gemato/exceptions.py
+++ b/gemato/exceptions.py
@@ -291,5 +291,7 @@ class ManifestInsecureHashes(GematoException):
self.hashes = hashes
def __str__(self):
+ if not self.hashes:
+ return "No hashes found when at least one secure hash is required"
return ("Some of the requested hashes are considered insecure: "
f"{' '.join(self.hashes)}")
diff --git a/gemato/verify.py b/gemato/verify.py
index 44a639f..1a951c0 100644
--- a/gemato/verify.py
+++ b/gemato/verify.py
@@ -129,7 +129,8 @@ def get_file_metadata(path, hashes):
yield ret
-def verify_path(path, e, expected_dev=None, last_mtime=None):
+def verify_path(path, e, expected_dev=None, last_mtime=None,
+ require_secure_hash=False):
"""
Verify the file at system path @path against the data in entry @e.
The path/filename is not matched against the entry -- the correct
@@ -149,6 +150,9 @@ def verify_path(path, e, expected_dev=None, last_mtime=None):
to the previous file verification. If the file is not newer
than that, the checksum verification is skipped.
+ If @require_secure_hash is True, the file must have at least one
+ hash that is considered cryptographically secure.
+
Each name can be:
- __exists__ (boolean) to indicate whether the file existed,
- __type__ (string) as a human-readable description of file type,
@@ -172,6 +176,11 @@ def verify_path(path, e, expected_dev=None, last_mtime=None):
checksums = list(filter(is_hash_supported, e.checksums))
if not checksums and e.checksums:
raise ManifestNoSupportedHashes(e)
+ if require_secure_hash:
+ # Note: even if we require secure hashes, we verify all of them
+ secure_hashes = list(filter(is_hash_secure, checksums))
+ if not secure_hashes:
+ raise ManifestInsecureHashes(checksums)
with contextlib.closing(get_file_metadata(path, checksums)) as g:
# 1. verify whether the file existed in the first place
diff --git a/tests/test_verify.py b/tests/test_verify.py
index 7ee4545..43f2830 100644
--- a/tests/test_verify.py
+++ b/tests/test_verify.py
@@ -104,7 +104,12 @@ def get_checksums(path):
'__size__': hashes['__size__'],
}
-
+EMPTY_CHECKSUMS = {
+ "MD5": "d41d8cd98f00b204e9800998ecf8427e",
+ "SHA1": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
+ "SHA256": "e3b0c44298fc1c149afbf4c8996fb924"
+ "27ae41e4649b934ca495991b7852b855",
+}
TEST_PATH_SIZES = {
'empty-file': 0,
'regular-file': 43,
@@ -112,8 +117,8 @@ TEST_PATH_SIZES = {
'/proc/version': 0,
}
TEST_PATH_CHECKSUMS = {
- 'empty-file': {'MD5': 'd41d8cd98f00b204e9800998ecf8427e',
- 'SHA1': 'da39a3ee5e6b4b0d3255bfef95601890afd80709',
+ 'empty-file': {'MD5': EMPTY_CHECKSUMS["MD5"],
+ 'SHA1': EMPTY_CHECKSUMS["SHA1"],
'__size__': TEST_PATH_SIZES['empty-file'],
},
'regular-file': {'MD5': '9e107d9d372bb6826bd81d3542a419d6',
@@ -466,6 +471,29 @@ def test_insecure_hashes(test_tree, entry_hash, hashes_arg, insecure):
@pytest.mark.parametrize(
+ "entry_hash,insecure",
+ [("", True),
+ ("MD5", True),
+ ("SHA1", True),
+ ("SHA256", False),
+ ("MD5 SHA1", True),
+ ("SHA1 SHA256", False),
+ ])
+def test_verify_insecure_hashes(test_tree, entry_hash, insecure):
+ checksums = {}
+ for h in entry_hash.split():
+ checksums[h] = EMPTY_CHECKSUMS[h]
+
+ ctx = (pytest.raises(ManifestInsecureHashes) if insecure
+ else contextlib.nullcontext())
+ with ctx:
+ verify_path(
+ test_tree / "empty-file",
+ new_manifest_entry("DATA", "empty-file", 0, checksums),
+ require_secure_hash=True)
+
+
+@pytest.mark.parametrize(
'a_cls,a_name,a_args,b_cls,b_name,b_args,expected,diff',
[('DATA', 'test', [0, {'MD5': 'd41d8cd98f00b204e9800998ecf8427e'}],
'DATA', 'test', [0, {'MD5': 'd41d8cd98f00b204e9800998ecf8427e'}],