From 1a00d87f454e9294325752e838f9fa50c19d48ff Mon Sep 17 00:00:00 2001 From: Vladimir Diaz Date: Fri, 3 Mar 2017 14:45:19 -0500 Subject: [PATCH] Try to prevent duplicate keys It is possible for the 'signatures' field of metadata to contain duplicates. Same key, but different KEYIDs due to multiple hash algorithms being used to generate their keyid. --- tests/test_sig.py | 13 ++++++++++++- tuf/sig.py | 25 ++++++++++++++++++++----- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/tests/test_sig.py b/tests/test_sig.py index 43c5050518..0245e95663 100755 --- a/tests/test_sig.py +++ b/tests/test_sig.py @@ -28,6 +28,7 @@ import unittest import logging +import copy import tuf import tuf.log @@ -201,9 +202,18 @@ def test_get_signature_status_below_threshold(self): signable = {'signed' : 'test', 'signatures' : []} signable['signatures'].append(securesystemslib.keys.create_signature( - KEYS[0], signable['signed'])) + KEYS[0], signable['signed'])) + + copy_of_key = copy.deepcopy(KEYS[0]) + copy_of_key['keyid'] = '123456' + + signable['signatures'].append(securesystemslib.keys.create_signature( + copy_of_key, signable['signed'])) + print('signable signatures: ' + repr(signable['signatures'])) tuf.keydb.add_key(KEYS[0]) + tuf.keydb.add_key(copy_of_key) + threshold = 2 roleinfo = tuf.formats.make_role_metadata( [KEYS[0]['keyid'], @@ -211,6 +221,7 @@ def test_get_signature_status_below_threshold(self): tuf.roledb.add_role('Root', roleinfo) sig_status = tuf.sig.get_signature_status(signable, 'Root') + print('sig_status: ' + repr(sig_status)) self.assertEqual(2, sig_status['threshold']) self.assertEqual([KEYS[0]['keyid']], sig_status['good_sigs']) diff --git a/tuf/sig.py b/tuf/sig.py index d572f92be6..7bda41315a 100755 --- a/tuf/sig.py +++ b/tuf/sig.py @@ -67,10 +67,11 @@ def get_signature_status(signable, role=None, repository_name='default', Return a dictionary representing the status of the signatures listed in 'signable'. Given an object conformant to SIGNABLE_SCHEMA, a set of public - keys in 'tuf.keydb', a set of roles in 'tuf.roledb', and a role, - the status of these signatures can be determined. This method will iterate - the signatures in 'signable' and enumerate all the keys that are valid, - invalid, unrecognized, unauthorized, or generated using an unknown method. + keys in 'tuf.keydb', a set of roles in 'tuf.roledb', and a role, the status + of these signatures can be determined. This method will iterate the + signatures in 'signable' and enumerate all of the unique keys that are + valid, invalid, unrecognized, unauthorized, or generated using an unknown + method. signable: @@ -151,7 +152,12 @@ def get_signature_status(signable, role=None, repository_name='default', signed = signable['signed'] signatures = signable['signatures'] - # Iterate the signatures and enumerate the signature_status fields. + # To avoid duplicates, maintain a list of unique keys that are loaded. + # Duplicates might occur if the same key (a valid, but different keyid) is + # loaded with a different KEYID hash algorithm. + loaded_keys = [] + + # Iterate signatures and enumerate the signature_status fields. # (i.e., good_sigs, bad_sigs, etc.). for signature in signatures: sig = signature['sig'] @@ -166,12 +172,17 @@ def get_signature_status(signable, role=None, repository_name='default', unknown_sigs.append(keyid) continue + # Has 'key' already been processed (via the same, or different, KEYID)? + if key['keyval'] in loaded_keys: + continue + # Does the signature use an unknown key signing method? try: valid_sig = securesystemslib.keys.verify_signature(key, signature, signed) except securesystemslib.exceptions.UnknownMethodError: unknown_method_sigs.append(keyid) + loaded_keys.append(key['keyval']) continue # We are now dealing with either a trusted or untrusted key... @@ -185,6 +196,7 @@ def get_signature_status(signable, role=None, repository_name='default', if keyid not in keyids: untrusted_sigs.append(keyid) + loaded_keys.append(key['keyval']) continue # Unknown role, re-raise exception. @@ -194,14 +206,17 @@ def get_signature_status(signable, role=None, repository_name='default', # This is an unset role, thus an unknown signature. else: unknown_sigs.append(keyid) + loaded_keys.append(key['keyval']) continue # Identify good/authorized key. good_sigs.append(keyid) + loaded_keys.append(key['keyval']) else: # This is a bad signature for a trusted key. bad_sigs.append(keyid) + loaded_keys.append(key['keyval']) # Retrieve the threshold value for 'role'. Raise # securesystemslib.exceptions.UnknownRoleError if we were given an invalid