-
Notifications
You must be signed in to change notification settings - Fork 287
Description
Summary and Impact
This is a bug that occurs when root metadata is being verified before being written. This pre-write verification is intended to prevent the writing of metadata that would not be verifiable by a client. The code is flawed, and so it is readily possible to produce root metadata that will not be verifiable by a client.
Note that this bug does not result in incorrect client verification behavior, and so is not strictly a security issue. Problems can result from this behavior, however.
Background and Details
When writing new metadata (e.g. using repository_tool.write*), the write stack employs repository_lib._generate_and_write_metadata().
_generate_and_write_metadata:
- signs the metadata based on what keyids are noted in
roledb._roledb_dict[<repo>][<role>]['signing_keyids'] - checks to make sure that the resulting signed metadata is correct / can be verified
- writes the metadata file
There is a substantial bug in step 2 that results in this verification check failing to catch root metadata that a client might reject. Note that the way that step 1 works will be altered by #846 (alters internal metadata storage to match the written metadata format) and that the bug in step 2 will also be fixed by #846. It may be worth fixing this bug in parallel, however, and it must in any case be recorded.
Root metadata is a bit special. Any other top-level metadata can be verified by simply looking at the contemporaneous root metadata. Root metadata itself dictates the keys expected for verification of root metadata, however, and that means that (e.g.) clients will use version 5 of root to verify version 6 of root. To generalize: in order to verify version V of root, you must verify that it has good signatures from BOTH:
- at least the threshold and keyids for root from version V-1 of root
- at least the threshold and keyids for root from version V of root (i.e. the version being verified)
We don't want users of repository_tool to write metadata that can't be verified, so we check that; however, we do the verification against expected keyids & threshold from root version V-1 incorrectly. In particular, when we use repository_tool to update root's expectations of root (using repository_tool.add_verification_key(), repository_tool.remove_verification_key(), and repository_tool.threshold()), old values are saved in roledb._roledb_dict[<repo>][<role>]['previous_threshold'] and ...['previous_keyids'], but:
remove_verification_keydoesn't note prior values in those variablesadd_verification_keyandthresholdoverwrite what they last added to those variables, resulting in the wrong values if e.g. you add two verification keys between one root version and the next, or if (much less likely) you switch the threshold value twice before writing.
The Fix:
- If there's already a value for
...['previous_keyids'], don't overwrite it. The same goes for `...['previous_threshold']. - Empty the values on write.
#846 should also result in a fix to this, with slightly different properties, as those values will be moved.