├── .gitignore ├── LICENSE ├── POUFs ├── POUF-links ├── TAF-POUF │ └── pouf2.md └── reference-POUF │ └── pouf1.md ├── README.md ├── images └── figure-1-tap4.svg ├── merkletap-1.jpg ├── tap1-1.dot ├── tap1-1.png ├── tap1.md ├── tap10.md ├── tap11.md ├── tap12.md ├── tap13.md ├── tap14.md ├── tap15.md ├── tap16.md ├── tap17.md ├── tap18.md ├── tap19.md ├── tap2.md ├── tap20.md ├── tap3.md ├── tap4.md ├── tap5.md ├── tap6.md ├── tap7.md ├── tap8.md └── tap9.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | # Community Specification License 1.0 2 | 3 | **The Purpose of this License.** This License sets forth the terms under which 1) Contributor will participate in and contribute to the development of specifications, standards, best practices, guidelines, and other similar materials under this Working Group, and 2) how the materials developed under this License may be used. It is not intended for source code. Capitalized terms are defined in the License’s last section. 4 | 5 | **1. Copyright.** 6 | 7 | **1.1. Copyright License.** Contributor grants everyone a non-sublicensable, perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as expressly stated in this License) copyright license, without any obligation for accounting, to reproduce, prepare derivative works of, publicly display, publicly perform, and distribute any materials it submits to the full extent of its copyright interest in those materials. Contributor also acknowledges that the Working Group may exercise copyright rights in the Specification, including the rights to submit the Specification to another standards organization. 8 | 9 | **1.2. Copyright Attribution.** As a condition, anyone exercising this copyright license must include attribution to the Working Group in any derivative work based on materials developed by the Working Group. That attribution must include, at minimum, the material’s name, version number, and source from where the materials were retrieved. Attribution is not required for implementations of the Specification. 10 | 11 | **2. Patents.** 12 | 13 | **2.1. Patent License.** 14 | 15 | **2.1.1. As a Result of Contributions.** 16 | 17 | **2.1.1.1. As a Result of Contributions to Draft Specifications.** Contributor grants Licensee a non-sublicensable, perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as expressly stated in this License) license to its Necessary Claims in 1) Contributor’s Contributions and 2) to the Draft Specification that is within Scope as of the date of that Contribution, in both cases for Licensee’s Implementation of the Draft Specification, except for those patent claims excluded by Contributor under Section 3. 18 | 19 | **2.1.1.2. For Approved Specifications.** Contributor grants Licensee a non-sublicensable, perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as expressly stated in this License) license to its Necessary Claims included the Approved Specification that are within Scope for Licensee’s Implementation of the Approved Specification, except for those patent claims excluded by Contributor under Section 3. 20 | 21 | **2.1.2. Patent Grant from Licensee.** Licensee grants each other Licensee a non-sublicensable, perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as expressly stated in this License) license to its Necessary Claims for its Implementation, except for those patent claims excluded under Section 3. 22 | 23 | **2.1.3. Licensee Acceptance.** The patent grants set forth in Section 2.1 extend only to Licensees that have indicated their agreement to this License as follows: 24 | 25 | **2.1.3.1. Source Code Distributions.** For distribution in source code, by including this License in the root directory of the source code with the Implementation; 26 | 27 | **2.1.3.2. Non-Source Code Distributions.** For distribution in any form other than source code, by including this License in the documentation, legal notices, via notice in the software, and/or other written materials provided with the Implementation; or 28 | 29 | **2.1.3.3. Via Notices.md.** By issuing pull request or commit to the Specification’s repository’s Notices.md file by the Implementer’s authorized representative, including the Implementer’s name, authorized individual and system identifier, and Specification version. 30 | 31 | **2.1.4. Defensive Termination.** If any Licensee files or maintains a claim in a court asserting that a Necessary Claim is infringed by an Implementation, any licenses granted under this License to the Licensee are immediately terminated unless 1) that claim is directly in response to a claim against Licensee regarding an Implementation, or 2) that claim was brought to enforce the terms of this License, including intervention in a third-party action by a Licensee. 32 | 33 | **2.1.5. Additional Conditions.** This License is not an assurance (i) that any of Contributor’s copyrights or issued patent claims cover an Implementation of the Specification or are enforceable or (ii) that an Implementation of the Specification would not infringe intellectual property rights of any third party. 34 | 35 | **2.2. Patent Licensing Commitment.** In addition to the rights granted in Section 2.1, Contributor agrees to grant everyone a no charge, royalty-free license on reasonable and non-discriminatory terms to Contributor’s Necessary Claims that are within Scope for: 36 | 1) Implementations of a Draft Specification, where such license applies only to those Necessary Claims infringed by implementing Contributor's Contribution(s) included in that Draft Specification, and 37 | 2) Implementations of the Approved Specification. 38 | 39 | This patent licensing commitment does not apply to those claims subject to Contributor’s Exclusion Notice under Section 3. 40 | 41 | **2.3. Effect of Withdrawal.** Contributor may withdraw from the Working Group by issuing a pull request or commit providing notice of withdrawal to the Working Group repository’s Notices.md file. All of Contributor’s existing commitments and obligations with respect to the Working Group up to the date of that withdrawal notice will remain in effect, but no new obligations will be incurred. 42 | 43 | **2.4. Binding Encumbrance.** This License is binding on any future owner, assignee, or party who has been given the right to enforce any Necessary Claims against third parties. 44 | 45 | **3. Patent Exclusion.** 46 | 47 | **3.1. As a Result of Contributions.** Contributor may exclude Necessary Claims from its licensing commitments incurred under Section 2.1.1 by issuing an Exclusion Notice within 45 days of the date of that Contribution. Contributor may not issue an Exclusion Notice for any material that has been included in a Draft Deliverable for more than 45 days prior to the date of that Contribution. 48 | 49 | **3.2. As a Result of a Draft Specification Becoming an Approved Specification.** Prior to the adoption of a Draft Specification as an Approved Specification, Contributor may exclude Necessary Claims from its licensing commitments under this Agreement by issuing an Exclusion Notice. Contributor may not issue an Exclusion Notice for patents that were eligible to have been excluded pursuant to Section 3.1. 50 | 51 | **4. Source Code License.** Any source code developed by the Working Group is solely subject the source code license included in the Working Group’s repository for that code. If no source code license is included, the source code will be subject to the MIT License. 52 | 53 | **5. No Other Rights.** Except as specifically set forth in this License, no other express or implied patent, trademark, copyright, or other rights are granted under this License, including by implication, waiver, or estoppel. 54 | 55 | **6. Antitrust Compliance.** Contributor acknowledge that it may compete with other participants in various lines of business and that it is therefore imperative that they and their respective representatives act in a manner that does not violate any applicable antitrust laws and regulations. This License does not restrict any Contributor from engaging in similar specification development projects. Each Contributor may design, develop, manufacture, acquire or market competitive deliverables, products, and services, and conduct its business, in whatever way it chooses. No Contributor is obligated to announce or market any products or services. Without limiting the generality of the foregoing, the Contributors agree not to have any discussion relating to any product pricing, methods or channels of product distribution, division of markets, allocation of customers or any other topic that should not be discussed among competitors under the auspices of the Working Group. 56 | 57 | **7. Non-Circumvention.** Contributor agrees that it will not intentionally take or willfully assist any third party to take any action for the purpose of circumventing any obligations under this License. 58 | 59 | **8. Representations, Warranties and Disclaimers.** 60 | 61 | **8.1. Representations, Warranties and Disclaimers.** Contributor and Licensee represents and warrants that 1) it is legally entitled to grant the rights set forth in this License and 2) it will not intentionally include any third party materials in any Contribution unless those materials are available under terms that do not conflict with this License. IN ALL OTHER RESPECTS ITS CONTRIBUTIONS ARE PROVIDED "AS IS." The entire risk as to implementing or otherwise using the Contribution or the Specification is assumed by the implementer and user. Except as stated herein, CONTRIBUTOR AND LICENSEE EXPRESSLY DISCLAIM ANY WARRANTIES (EXPRESS, IMPLIED, OR OTHERWISE), INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, CONDITIONS OF QUALITY, OR TITLE, RELATED TO THE CONTRIBUTION OR THE SPECIFICATION. IN NO EVENT WILL ANY PARTY BE LIABLE TO ANY OTHER PARTY FOR LOST PROFITS OR ANY FORM OF INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER FROM ANY CAUSES OF ACTION OF ANY KIND WITH RESPECT TO THIS AGREEMENT, WHETHER BASED ON BREACH OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, AND WHETHER OR NOT THE OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Any obligations regarding the transfer, successors in interest, or assignment of Necessary Claims will be satisfied if Contributor or Licensee notifies the transferee or assignee of any patent that it knows contains Necessary Claims or necessary claims under this License. Nothing in this License requires Contributor to undertake a patent search. If Contributor is 1) employed by or acting on behalf of an employer, 2) is making a Contribution under the direction or control of a third party, or 3) is making the Contribution as a consultant, contractor, or under another similar relationship with a third party, Contributor represents that they have been authorized by that party to enter into this License on its behalf. 62 | 63 | **8.2. Distribution Disclaimer.** Any distributions of technical information to third parties must include a notice materially similar to the following: “THESE MATERIALS ARE PROVIDED “AS IS.” The Contributors and Licensees expressly disclaim any warranties (express, implied, or otherwise), including implied warranties of merchantability, non-infringement, fitness for a particular purpose, or title, related to the materials. The entire risk as to implementing or otherwise using the materials is assumed by the implementer and user. IN NO EVENT WILL THE CONTRIBUTORS OR LICENSEES BE LIABLE TO ANY OTHER PARTY FOR LOST PROFITS OR ANY FORM OF INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER FROM ANY CAUSES OF ACTION OF ANY KIND WITH RESPECT TO THIS DELIVERABLE OR ITS GOVERNING AGREEMENT, WHETHER BASED ON BREACH OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, AND WHETHER OR NOT THE OTHER MEMBER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.” 64 | 65 | **9. Definitions.** 66 | 67 | **9.1. Affiliate.** “Affiliate” means an entity that directly or indirectly Controls, is Controlled by, or is under common Control of that party. 68 | 69 | **9.2. Approved Specification.** “Approved Specification” means the final version and contents of any Draft Specification designated as an Approved Specification as set forth in the accompanying Governance.md file. 70 | 71 | **9.3. Contribution.** “Contribution” means any original work of authorship, including any modifications or additions to an existing work, that Contributor submits for inclusion in a Draft Specification, which is included in a Draft Specification or Approved Specification. 72 | 73 | **9.4. Contributor.** “Contributor” means any person or entity that has indicated its acceptance of the License 1) by making a Contribution to the Specification, or 2) by entering into the Community Specification Contributor License Agreement for the Specification. Contributor includes its Affiliates, assigns, agents, and successors in interest. 74 | 75 | **9.5. Control.** “Control” means direct or indirect control of more than 50% of the voting power to elect directors of that corporation, or for any other entity, the power to direct management of such entity. 76 | 77 | **9.6. Draft Specification.** “Draft Specification” means all versions of the material (except an Approved Specification) developed by this Working Group for the purpose of creating, commenting on, revising, updating, modifying, or adding to any document that is to be considered for inclusion in the Approved Specification. 78 | 79 | **9.7. Exclusion Notice.** “Exclusion Notice” means a written notice made by making a pull request or commit to the repository’s Notices.md file that identifies patents that Contributor is excluding from its patent licensing commitments under this License. The Exclusion Notice for issued patents and published applications must include the Draft Specification’s name, patent number(s) or title and application number(s), as the case may be, for each of the issued patent(s) or pending patent application(s) that the Contributor is excluding from the royalty-free licensing commitment set forth in this License. If an issued patent or pending patent application that may contain Necessary Claims is not set forth in the Exclusion Notice, those Necessary Claims shall continue to be subject to the licensing commitments under this License. The Exclusion Notice for unpublished patent applications must provide either: (i) the text of the filed application; or (ii) identification of the specific part(s) of the Draft Specification whose implementation makes the excluded claim a Necessary Claim. If (ii) is chosen, the effect of the exclusion will be limited to the identified part(s) of the Draft Specification. 80 | 81 | **9.8. Implementation.** “Implementation” means making, using, selling, offering for sale, importing or distributing any implementation of the Specification 1) only to the extent it implements the Specification and 2) so long as all required portions of the Specification are implemented. 82 | 83 | **9.9. License.** “License” means this Community Specification License. 84 | 85 | **9.10. Licensee.** “Licensee” means any person or entity that has indicated its acceptance of the License as set forth in Section 2.1.3. Licensee includes its Affiliates, assigns, agents, and successors in interest. 86 | 87 | **9.11. Necessary Claims.** “Necessary Claims” are those patent claims, if any, that a party owns or controls, including those claims later acquired, that are necessary to implement the required portions (including the required elements of optional portions) of the Specification that are described in detail and not merely referenced in the Specification. 88 | 89 | **9.12. Specification.** “Specification” means a Draft Specification or Approved Specification included in the Working Group’s repository subject to this License, and the version of the Specification implemented by the Licensee. 90 | 91 | **9.13. Scope.** “Scope” has the meaning as set forth in the accompanying Scope.md file included in this Specification’s repository. Changes to Scope do not apply retroactively. If no Scope is provided, each Contributor’s Necessary Claims are limited to that Contributor’s Contributions. 92 | 93 | **9.14. Working Group.** “Working Group” means this project to develop specifications, standards, best practices, guidelines, and other similar materials under this License. 94 | 95 | 96 | 97 | *The text of this Community Specification License is Copyright 2020 Joint Development Foundation and is licensed under the Creative Commons Attribution 4.0 International License available at https://creativecommons.org/licenses/by/4.0/.* 98 | 99 | SPDX-License-Identifier: CC-BY-4.0 100 | -------------------------------------------------------------------------------- /POUFs/POUF-links: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theupdateframework/taps/a30461fba0d351ae9a2dc831e5c52cfc1e8deafb/POUFs/POUF-links -------------------------------------------------------------------------------- /POUFs/TAF-POUF/pouf2.md: -------------------------------------------------------------------------------- 1 | * POUF: 2 | * Title: The Archive Framework 3 | * Version: 1 4 | * Last-Modified: 5 | * Author: Renata Vaderna 6 | * Status: Draft 7 | * TUF Version Implemented: 8 | * Implementation Version(s) Covered: 9 | * Content-Type: text/markdown 10 | * Created: 11 | 12 | # Abstract 13 | 14 | This POUF describes the protocol, operations, usage, and formats for the 15 | implementation of TUF designed to distribute Git repositories. This instance is 16 | known as The Archive Framework or TAF and leverages TAP-19 that adds support in 17 | TUF for content addressable artifacts and their native hashing routines. 18 | 19 | # Protocol 20 | 21 | This POUF currently uses a subset of the JSON object format, with floating-point 22 | numbers omitted. When calculating the digest of an object, we use the 23 | ["canonical JSON" subdialect](http://wiki.laptop.org/go/Canonical_JSON) and 24 | implemented in securesystemslib. As TAF uses the TUF reference implementation 25 | for metadata generation, it implicitly depends on the reference implementation 26 | POUF’s protocols. 27 | 28 | Metadata and target files are stored in a git repository referred to as an 29 | authentication repository. An authentication repository contains information 30 | needed to securely clone and update other git repositories (referred to as 31 | target repositories), including their URLs and additional custom data that can 32 | be used by TAF's implementers. This is specified in special target files, 33 | `repositories.json` and `mirrors.json` - regular TUF target files (whose 34 | lengths and hashes are stored in `targets.json` and which are signed by the 35 | top-level targets role) which are of special importance to TAF. 36 | 37 | TAF focuses on protecting git repositories from unauthorized pushes. It is 38 | designed to record valid commits for target repositories in the authentication 39 | repository. If an attacker manages to compromise a user who has write access to 40 | protected repositories and creates new commits, TAF will detect this by 41 | comparing these new commits to a list of valid commits specified in the 42 | authentication repository. In order to register these new commits, the attacker 43 | has to modify TUF metadata files as well. Unless they also gain access to 44 | `targets` or `root` keys, they cannot do this without the attempt being 45 | detected by TAF. TAF's users are encouraged to store signing keys for the 46 | `target` and `root` roles offline on hardware tokens to ensure their safety. 47 | 48 | In essence, while TAF ensures the validity of commits in target repositories, 49 | it makes no claims about the integrity of their contents. TAF relies on Git's 50 | default artifact integrity protection. Git, however, still primarily relies on 51 | SHA-1, even though it has been proven that this hash function is vulnerable to 52 | collision attacks. If an attacker manages to gain access to the original target 53 | repositories, they could potentially exploit the SHA-1 weakness. On the other hand, 54 | authentication repositories store lists of valid URLs of target repositories, 55 | ensuring that users are protected from _mirrors_ of legitimate repositories presenting 56 | a colliding artifact in place of the original artifact. These URLs are defined manually 57 | and can only be modified by someone who has a `targets` key. If a target repository 58 | is not owned by the same person or organization that is setting up an authentication 59 | repository, it is a hard requirement to directly contact the owner who will be 60 | able to confirm authenticity of the repository in question. 61 | 62 | In order to take advantage of TAF's validations, a client can download an 63 | authentication repository and all of the referenced repositories by running 64 | TAF’s updater and specifying the authentication repository’s URL. Repositories 65 | are cloned and updated using git. The updater runs validation before 66 | permanently storing anything on the client’s machine: 67 | * An authentication repository is cloned as a bare repository inside the 68 | user’s temp directory (so no worktree is checked out) 69 | * This repository is then validated. Metadata and target files are read using 70 | `git show` 71 | * If validation is successful, the repository is cloned/new changes are 72 | pulled, once again using Git 73 | 74 | 75 | # Operations 76 | 77 | WIP 78 | 79 | # Usage 80 | 81 | In order to use the system, it is necessary to set up an authentication 82 | repository - initialize a TUF repository (generate TUF metadata files and sign 83 | them using offline keys, either loaded from the filesystem or YubiKeys) and 84 | commit the changes. TAF contains a command line interface which can be used to 85 | create and update authentication repositories (add new target files and signing 86 | keys, extend expiration dates of metadata files, generate keystore files and 87 | set up YubiKeys). For example, a new authentication repository can be created 88 | using the `taf repo create repo_path` command. Detailed explanation and 89 | instructions are available in the official documentation 90 | https://github.com/openlawlibrary/taf/blob/master/docs/quickstart.md. 91 | 92 | TAF's main purpose is to provide archival authentication, which means that it 93 | is not only the current state of the repositories that is validated - 94 | correctness of all past versions needs to be checked as well. A state is valid 95 | if the authentication repository at a certain revision (commit) is a valid TUF 96 | repository and target repositories are valid according to the data defined in 97 | the authentication repository. So, if `targets.json` is updated, 98 | `snapshot.json` and `timestamp.json` need to be updated in the same commit or 99 | the repository will not be valid. This ensures that a client cannot check out 100 | an invalid version of the repository. Moreover, validation of the 101 | authentication repository also ensures that versions of metadata files in older 102 | revisions are lower than in newer revisions. Once the metadata and target 103 | files are validated, they are used to check correctness of the referenced git 104 | repositories - do actual commits in those repositories correspond to the 105 | commits listed in the authentication repository. 106 | 107 | To sum up, TAF extends the reference implementation by storing the metadata and 108 | target files in a git repository and making sure that all changes are committed 109 | after every valid update. 110 | 111 | # Formats 112 | 113 | The metadata generated to support Git repositories are largely the same as 114 | those described in the TUF specification and POUF-1. The key difference is in 115 | the enumeration of Targets. 116 | 117 | Firstly, while TUF identifies individual targets by their location relative to 118 | the mirror’s base URL, this POUF uses a URI to identify the specific Git 119 | namespace in a target repository. This URI is also used to locate the 120 | repository itself. The URI must use `git` as the scheme, clearly indicating 121 | that the entry pertains to a Git object. 122 | 123 | For metadata of some repository, a Targets entry is expected to map to a 124 | specific Git branch or tag. For each entry, whether a branch or a tag, a hash 125 | value must be recorded that clearly identifies the expected commit at the 126 | corresponding Git reference. As per TAP-19 that adds support for content 127 | addressable systems and their native hashing routines, instead of calculating 128 | the hash afresh for a particular Git reference, the identifier of the commit at 129 | the tip of the branch or that the tag points to must be used. 130 | 131 | Apart from the hashes and custom field, a Targets entry is also expected to 132 | record the length of the artifact. This length is vital in avoiding endless 133 | data attacks. However, there is no clear mapping of a length for a particular 134 | commit object. Therefore, for Git specific implementations, the length field 135 | may be omitted. However, implementations are free to choose sane limits for how 136 | much data is fetched when pulling from a Git repository. 137 | 138 | # Security Audit 139 | 140 | None yet. 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TUF Augmentation Proposals (TAPs) 2 | 3 | ## Accepted 4 | 5 | * [TAP 1: TAP Purpose and Guidelines](tap1.md) 6 | * [TAP 2: TAP template](tap2.md) 7 | * [TAP 3: Multi-role delegations](tap3.md) 8 | * [TAP 4: Multiple repository consensus on entrusted targets](tap4.md) 9 | * [TAP 6: Include specification version in metadata](tap6.md) 10 | * [TAP 8: Key rotation and explicit self-revocation](tap8.md) 11 | * [TAP 9: Mandatory metadata signing schemes](tap9.md) 12 | * [TAP 10: Remove native support for compressed metadata](tap10.md) 13 | * [TAP 11: Using POUFs for Interoperability](tap11.md) 14 | * [TAP 12: Improving keyid flexibility](tap12.md) 15 | * [TAP 15: Succinct hashed bin delegations](tap15.md) 16 | * [TAP 20: Self-revocation](tap20.md) 17 | 18 | ## Draft 19 | 20 | * [TAP 13: User Selection of the Top-Level Target Files Through Mapping Metadata](tap13.md) 21 | * [TAP 16: Snapshot Merkle Trees](tap16.md) 22 | * [TAP 17: Remove Signature Wrapper from the TUF Specification](tap17.md) 23 | * [TAP 18: Ephemeral identity verification using sigstore's Fulcio for TUF developer key management](tap18.md) 24 | * [TAP 19: Content Addressable Systems and TUF](tap19.md) 25 | 26 | ## Deferred 27 | 28 | * [TAP 14: Managing TUF Versions](tap14.md) 29 | 30 | ## Rejected 31 | 32 | * [TAP 5: Setting URLs for roles in the root metadata file](tap5.md) 33 | * [TAP 7: Conformance testing](tap7.md) 34 | 35 | 36 | ## License 37 | 38 | This work is distributed under the Community Specification License 1.0. 39 | Please see [LICENSE](LICENSE) for more details. 40 | 41 | 42 | ## Acknowledgements 43 | 44 | This project is managed by Prof. Justin Cappos and other members of the [Secure 45 | Systems Lab](https://ssl.engineering.nyu.edu/) at NYU. 46 | 47 | This material is based upon work supported by the National Science Foundation 48 | under Grant Nos. CNS-1345049 and CNS-0959138. Any opinions, findings, and 49 | conclusions or recommendations expressed in this material are those of the 50 | author(s) and do not necessarily reflect the views of the National Science 51 | Foundation. 52 | -------------------------------------------------------------------------------- /merkletap-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theupdateframework/taps/a30461fba0d351ae9a2dc831e5c52cfc1e8deafb/merkletap-1.jpg -------------------------------------------------------------------------------- /tap1-1.dot: -------------------------------------------------------------------------------- 1 | // Converted into a png with: dot -Tpng -o tap1-1.png tap1-1.dot 2 | digraph { 3 | node[shape=box, style=rounded] 4 | 5 | {rank=same; Accepted, Draft, Final} 6 | {rank=same; Superseded, Rejected, Withdrawn} 7 | 8 | Draft -> Accepted 9 | Accepted -> Final 10 | Draft -> Deferred 11 | Deferred -> Draft 12 | Draft -> Rejected 13 | Draft -> Withdrawn 14 | Final -> Superseded 15 | Draft -> Active 16 | Active -> Superseded 17 | } 18 | -------------------------------------------------------------------------------- /tap1-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theupdateframework/taps/a30461fba0d351ae9a2dc831e5c52cfc1e8deafb/tap1-1.png -------------------------------------------------------------------------------- /tap1.md: -------------------------------------------------------------------------------- 1 | * TAP: 1 2 | * Title: TAP Purpose and Guidelines 3 | * Version: 2 4 | * Last-Modified: 30-Nov-2020 5 | * Author: Trishank Karthik Kuppusamy, Lois Anne DeLong, Justin Cappos, Joshua Lock 6 | * Status: Active 7 | * Content-Type: text/markdown 8 | * Created: 07-Sep-2016 9 | * Post-History: 08-Sep-2016 10 | 11 | # What is a TAP? 12 | 13 | TAP stands for TUF Augmentation Proposal and is largely modeled after a similar type of document used in the Python Enhancement Proposal (https://www.python.org/dev/peps/pep-0001/) process. A TAP is a design document that either provides information to the TUF community, or describes a new feature for TUF or for its processes or environment. The TAP should provide both a concise technical specification of the feature and a rationale for the feature's inclusion. 14 | 15 | We intend TAPs to be the primary mechanisms for proposing major new features, for collecting community input on an issue, and for documenting the design decisions that have gone into TUF. The TAP author is responsible for building consensus within the community and documenting dissenting opinions. 16 | 17 | Because the TAPs are maintained as text files in a versioned repository, their revision history is the historical record of the feature proposal. 18 | 19 | # TAP Types 20 | 21 | There are two kinds of TAPs: 22 | 1. A **Standardization** TAP proposes new features for, or changes to the existing behavior of, the TUF specification. 23 | 2. An **Informational** TAP describes a design issue, or provides general guidelines or information for TUF implementers. 24 | 25 | # TAP Status 26 | 27 | The status of a TAP indicates its progress through the development process. The different status classifications are defined below. Unless otherwise specified, each status applies to both kinds of TAP. 28 | 29 | * A **Draft** TAP is one that has been proposed and is actively being worked on. 30 | * **Active** TAPs are Informational TAPs that are expected to change as the specification and the processes around it evolve. 31 | * An **Accepted** Standardization TAP is deemed ready to be integrated into the specification and augmented reference implementation. 32 | * **Deferred** TAPs are potentially good ideas which are not being actively developed, or where progress is not being made. 33 | * A **Rejected** TAP is one which the [TAP editors](#tap-editors) have decided is ultimately not a good idea. 34 | * **Withdrawn** TAPs are submissions which the champion, or lead author, of the TAP has decided are no longer worth pursuing. 35 | * **Final** TAPs are complete and will no longer change. For Standardization TAPs this means the proposed changes have been merged into the augmented reference implementation and the specification. 36 | * A **Superseded** TAP is one which has been rendered obsolete by a newer TAP. 37 | 38 | # TAP Workflow 39 | 40 | ## Consensus Builder 41 | 42 | The consensus builder for the TUF specification is Prof. Justin Cappos of the NYU Secure Systems Lab. 43 | Ultimate authority for changes to the TUF specification, including changes proposed through this TAP process, falls to the specification's consensus builder. 44 | 45 | ## TAP Editors 46 | 47 | The TAP Editors are a team of core contributors to the TUF project who are responsible for reviewing and approving or rejecting any proposed TAPs. 48 | 49 | ## Start with an Idea 50 | 51 | The TAP process begins with a new idea for TUF. It is highly recommended that each TAP contain only a single key proposal or new idea. Small enhancements or patches often do not require a TAP and can be injected into the TUF development workflow with a patch submission to the [TUF specification](https://github.com/theupdateframework/specification). 52 | 53 | The more focused the TAP, the more successful it tends to be. The [TAP Editors](#tap-editors) reserve the right to reject TAP proposals if they appear too unfocused or too broad. If in doubt, split your TAP into several well-focused ones. 54 | 55 | Each TAP MUST have a champion -- someone who writes the TAP using the style and format described below, shepherds the discussions in the appropriate forums, and attempts to build community consensus around the idea. The TAP champion (a.k.a. Author) SHOULD first attempt to ascertain whether the idea is TAP-able. Posting to the TUF [issue tracker](https://github.com/theupdateframework/specification/issues), the [#tuf channel](https://cloud-native.slack.com/archives/C8NMD3QJ3) on CNCF Slack, or the [TUF mailing list](https://groups.google.com/forum/?fromgroups#!forum/theupdateframework) are good ways to go about this. 56 | 57 | ## Submitting a TAP 58 | 59 | Once the champion has asked the TUF community whether an idea has any chance of acceptance, a draft TAP SHALL be presented as a [pull request](https://github.com/theupdateframework/taps/pulls) to the TAPs repository. The draft MUST be written in TAP style as described below and in [TAP 2](tap2.md), or it will immediately fail review. 60 | 61 | Once a submission is approved for inclusion in the TAP repository, the TAP Editors will assign it a number, mark its status as "Draft", and merge the initial draft. The [TAP Editors](#tap-editors) will not unreasonably deny Draft status to a TAP. Reasons for denying a TAP include duplication of effort, being technically unsound, not providing proper motivation or addressing backwards compatibility, or not in keeping with the TUF philosophy. [TAP Editors](#tap-editors) may be consulted during the approval phase, with the [Consensus Builder](#consensus-builder) as the final arbiter of the draft's viability as a TAP. 62 | 63 | As updates are necessary, the TAP author can submit new versions by opening additional [pull requests](https://github.com/theupdateframework/taps/pulls) against the repository. 64 | 65 | Standardization TAPs consist of two parts, a design document and an augmented reference implementation. It is generally recommended that at least a prototype implementation be co-developed with the TAP, as ideas that sound good in principle sometimes turn out to be impractical when subjected to the test of implementation. However, a prototype is not required by the TAP process until the TAP is in the "Accepted" status. No TAP will be marked as "Final" until an augmented reference implementation is available. 66 | 67 | TAP authors are responsible for collecting community feedback on a TAP before submitting it for review. All comments should be gathered on a [GitHub issue](https://github.com/theupdateframework/taps/issues) specific to the TAP. It is recommended that feedback be solicited via the [TUF mailing list](https://groups.google.com/forum/?fromgroups#!forum/theupdateframework). 68 | 69 | ## TAP Review & Resolution 70 | 71 | Once feedback has been gathered, a change of the TAP to "Accepted" status MUST be requested via the TAPs [issue tracker](https://github.com/theupdateframework/taps/issues) or a [pull request](https://github.com/theupdateframework/taps/pulls). TAPs are reviewed by the [TAP Editors](#tap-editors), who may accept or reject a TAP or send it back to the author(s) for revision. For a TAP that is predetermined to be acceptable (e.g., it is an obvious win as-is and/or its implementation has already been checked in) the TUF team may also initiate a TAP review, first notifying the TAP author(s) and giving them a chance to make revisions. In order for a Standardization TAP to be "Accepted", it MUST have a corresponding prototype implementation for the reference implementation. 72 | 73 | In order to move a Standardization TAP from "Accepted" to "Final" status, the augmented reference implementation MUST be completed and merged, and any proposed specification changes MUST be integrated into the specification. 74 | 75 | For an Informational TAP, no changes are expected to the augmented reference implementation or specification. Therefore, a TAP may move to "Final" status, without moving through the "Accepted" status, once it is deemed ready by the TAP editors. 76 | 77 | Informational TAPs may take the status of "Active" if, like this TAP, it is expected to change as the specification and the processes around it evolve. 78 | 79 | A TAP can also be "Rejected," if it becomes evident to the TAP editors that the proposed change was not a good idea. In this case, the "Rejected" status serves as a record of this decision. The "Withdrawn" status serves a similar function. In this case, it is the author who has decided that the TAP is actually a bad idea, or has accepted that a competing proposal is a better alternative. 80 | 81 | When a TAP is Accepted, Rejected, or Withdrawn, the TAP should be updated accordingly. 82 | 83 | TAPs can also be "Superseded" by a different TAP, rendering the original obsolete. 84 | 85 | Possible paths for a TAP are: 86 | 87 | ![Diagram of TAP status flow](tap1-1.png) 88 | 89 | ## TAP Maintenance 90 | 91 | In general, TAPs are no longer modified after they have reached the "Final" state. Once a TAP has been completed, the Specification becomes the formal documentation of the expected behavior. 92 | Informational TAPs in the "Active" state may continue to be updated via pull request to the TAPs repository. 93 | 94 | # What belongs in a successful TAP? 95 | 96 | Each TAP SHOULD have the following parts: 97 | 98 | 1. *Preamble* -- [RFC 822](https://tools.ietf.org/html/rfc822) style headers containing meta-data about the TAP, including the TAP number, a short descriptive title (limited to a maximum of 44 characters), the names, and optionally the contact info for each author, etc. 99 | 100 | 2. *Abstract* -- a short (~200 word) description of the technical issue being addressed. 101 | 102 | 3. *Motivation* -- The motivation is critical for TAPs that want to change TUF. It should clearly explain why the existing framework specification is inadequate to address the problem that the TAP solves. TAP submissions without sufficient motivation may be rejected outright. 103 | 104 | 4. *Rationale* -- The rationale fleshes out the proposal by describing what motivated the design and why particular design decisions were made. It should describe any alternate designs that were considered and how the feature is supported in other frameworks using related works. The rationale should also provide evidence of consensus within the community and discuss important objections or concerns raised during discussion. 105 | 106 | 5. *Specification* -- The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for at least the current major TUF platforms (TUF, Notary, go-tuf). 107 | 108 | 6. *Security Analysis* -- The TAP should show, as simply as possible, why the proposal would not detract from existing security guarantees. (In other words, the proposal should either maintain or add to existing security.) This need not entail a mathematical proof. For example, it may suffice to provide a case-by-case analysis of key compromise over all foreseeable roles. To take another example, if a change is made to a delegation, it must preserve existing delegation semantics (unless the TAP makes a good argument for breaking those semantics). 109 | 110 | 7. *Backwards Compatibility* -- All TAPs that introduce backwards incompatibilities must include a section describing these incompatibilities, their severity, and how the author proposes to deal with them. TAP submissions without a sufficient backwards compatibility treatise may be rejected outright. 111 | 112 | 8. *Augmented Reference Implementation* -- The augmented reference implementation must be completed before any TAP is given "Final" status, but it need not be completed before the TAP is accepted as "Draft". While there is merit to the approach of reaching consensus on the specification and rationale before writing code, the principle of "rough consensus and running code" is still useful when it comes to resolving many discussions of API details. The final implementation must include test code and documentation appropriate for the TUF reference. 113 | 114 | 9. *Copyright* -- Each TAP must either be explicitly labeled as placed in the public domain (see this TAP as an example) or licensed under the [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/). 115 | 116 | # TAP Formats and Templates 117 | 118 | TAPs are UTF-8 encoded text files using the [Markdown](https://daringfireball.net/projects/markdown/) format. Markdown allows for rich markup that is still quite easy to read, but also results in good-looking and functional HTML. 119 | 120 | In-line with the Specification, the keywords "MUST," "MUST NOT," "REQUIRED," "SHALL," "SHALL NOT," "SHOULD," "SHOULD NOT," "RECOMMENDED," "MAY," and "OPTIONAL" in a TAP are to be interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119). 121 | 122 | [TAP 2](https://github.com/theupdateframework/taps/blob/master/tap2.md) contains a template for MarkDown TAPs. 123 | 124 | # TAP Header Preamble 125 | 126 | Each TAP MUST begin with an RFC 822 style header preamble. The headers MUST appear in the following order. Headers marked with "+" are OPTIONAL and are described below. All other headers are required. 127 | 128 | * TAP: 129 | * Title: 130 | * Version: 131 | * Last-Modified: 132 | * Author: 133 | * Type: 134 | * Status: 135 | * +Content-Type: 136 | * +Requires: 137 | * Created: 138 | * +TUF-Version: 139 | * +Replaces: 140 | * +Superseded-By: 141 | 142 | The Author header lists the names, and optionally the email addresses of all the authors/owners of the TAP. The format of the Author header value SHOULD be "Random J. User ". 143 | 144 | The format of a TAP is specified with a Content-Type header. The acceptable values are "text/markdown" for Markdown TAPs (see [TAP 2](https://github.com/theupdateframework/taps/blob/master/tap2.md)). Markdown ("text/markdown") is the default if no Content-Type header is present. 145 | 146 | The Created header records the date that the TAP was assigned a number and SHOULD be in dd-mmm-yyyy format, e.g. 14-Aug-2001. 147 | 148 | TAPs will typically have a TUF-Version header which indicates the version of TUF that the feature will be released with. TAPs that refer to processes or recommendations do not require a TUF-Version header. 149 | 150 | TAPs MAY have a Requires header, indicating the TAP numbers on which this TAP depends. 151 | 152 | TAPs MAY also have a Superseded-By header indicating that it has been rendered obsolete by a later document; the value is the number of the TAP that replaces the current document. The newer TAP must have a Replaces header containing the number of the TAP that it rendered obsolete. 153 | 154 | # Auxiliary Files 155 | 156 | TAPs MAY include auxiliary files such as diagrams. These files MUST be named ``tap-XXXX-Y.ext``, where "XXXX" is the TAP number, "Y" is a serial number (starting at 1), and "ext" is replaced by the actual file extension (e.g. "png"). 157 | 158 | # Reporting TAP Bugs, or Submitting TAP Updates 159 | 160 | The procedure for reporting a bug, or submitting a TAP update depends on several factors, such as the maturity of the TAP, the preferences of the TAP author, and the nature of the comments. For Draft or Accepted TAPs, feedback should be via the TAPs [issue tracker](https://github.com/theupdateframework/taps/issues) or as a pull request against the TAP in question. 161 | Once a TAP has been marked Final, bugs or corrections SHOULD be submitted to the TUF [issue tracker](https://github.com/theupdateframework/specification/issues) so that changes do not get lost. 162 | 163 | # Transferring TAP Ownership 164 | 165 | It occasionally becomes necessary to transfer ownership of TAPs to a new champion. In general, it is preferable to retain the original author as a co-author of the transferred TAP, but that is really up to the individual. A good reason to transfer ownership is because the original author no longer has the time or interest in updating it or following through with the TAP process, or is unreachable (or not responding to email). A bad reason to transfer ownership is because the author doesn't agree with the direction of the TAP. One aim of the TAP process is to try to build consensus around a TAP, but if that's not possible, an author can always submit a competing TAP. 166 | 167 | If you are interested in assuming ownership of a TAP, send a message stating that request to both the original author and the [TUF mailing list](https://groups.google.com/forum/?fromgroups#!forum/theupdateframework). If the original author does not respond to the email in a timely manner, the TUF team will make a unilateral decision, though such decisions may be reversible. 168 | 169 | # Copyright 170 | 171 | This document has been placed in the public domain. 172 | 173 | # Acknowledgements 174 | 175 | This TAP was heavily borrowed from [PEP 1](https://www.python.org/dev/peps/pep-0001/). 176 | -------------------------------------------------------------------------------- /tap10.md: -------------------------------------------------------------------------------- 1 | * TAP: 10 2 | * Title: Remove native support for compressed metadata 3 | * Version: 1 4 | * Last-Modified: 25-August-2017 5 | * Author: Vladimir Diaz 6 | * Status: Final 7 | * Content-Type: text/markdown 8 | * Created: 19-July-2017 9 | * Post-History: 25-July-2017 10 | * TUF-Version: 1.0.0 11 | 12 | # Abstract 13 | 14 | The specification allows repository maintainers to serve TUF metadata in 15 | compressed form, thereby reducing the amount of bandwidth needed by clients. 16 | Unfortunately, maliciously compressed metadata can potentially leave clients 17 | vulnerable to decompression attacks. Since native support for compressed 18 | metadata has been a source of complexity at the implementation level, the 19 | specification should instead recommend that compression be implemented at the 20 | presentation layer of the [OSI protocol 21 | stack](https://en.wikipedia.org/wiki/OSI_protocols), which is better suited to 22 | handle decompression of data. Once decompressed, metadata can be validated 23 | against the hashes and signatures listed in the Snapshot file. 24 | 25 | Relegating the use of compression minimizes code complexity, reduces the size 26 | of the Snapshot file, and doesn't require native protection against malicious 27 | archives, which can lead to corrupted installation environments. Compression 28 | code is tricky to write in a way that limits the potential for abuse. 29 | 30 | # Motivation 31 | 32 | This TAP has been motivated by the following issues: 33 | 34 | * A [zip bomb](https://en.wikipedia.org/wiki/Zip_bomb) is a "malicious archive 35 | file designed to crash or render useless the program or system reading it." An 36 | implementor needs to take extra steps to protect against decompression 37 | attacks while working with compressed metadata. 38 | 39 | * Compressed metadata leads to code complexity by requiring implementors to 40 | correctly write and read it. For example, logic has to be added to detect when 41 | compressed metedata is available on a repository. The code must also ensure 42 | consistent hashing of compressed metadata, which can be a problem with certain 43 | compression algorithms that append timestamps to compressed data. 44 | 45 | * The Snapshot file becomes unnecessarily large in size because it must list 46 | both compressed and uncompressed forms of the same metadata. Clients may 47 | request either form of particular metadata. 48 | 49 | * Some roles should be excluded from compression. The Timestamp and Root 50 | metadata files are not required to be compressed because the hash and version 51 | number of the former are unknown, and the latter does not benefit from 52 | compression. Special cases like this leads to inconsistent behavior and 53 | code. 54 | 55 | * The Snapshot file does not list the hashes of targets metadata, so an 56 | implementor is forced to decompress untrusted data. 57 | 58 | * Compressed metadata can potentially unpack to an unexpected directory 59 | or filename. This can lead to undesirable states, where target or metadata 60 | files are overwritten. An implementor might fail to check that [files in the 61 | archive do not lead to a malicious directory 62 | traversal](https://www.exploit-db.com/exploits/39680/) while decompressing, 63 | possibly [via 64 | symbolic links](https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=774660). 65 | 66 | # Rationale 67 | 68 | Adopters of the specification have argued that implementing native support for 69 | compression is non-trivial, and that they would prefer to handle compression 70 | with a standard approach. That is, decompressing metadata at layer 6 of the 71 | OSI model would be ideal and simplify matters. 72 | 73 | Compression is also only needed with large repositories. It should be left 74 | to an adopter to decide whether they want to compress metadata. 75 | 76 | # Specification 77 | 78 | This TAP does not propose a new feature, thus it does not describe new 79 | syntax and semantics. The only change is that the *compression_algorithms* 80 | attribute is removed from Root metadata, which specifies which compression 81 | algorithms are available on a repository. 82 | 83 | Old format of the "signed" portion of Root metadata: 84 | 85 |
 86 | {
 87 |   "_type" : "root",
 88 |   "compression_algorithms": [ COMPRESSION_ALGORITHM, ... ],
 89 |   "consistent_snapshot": CONSISTENT_SNAPSHOT,
 90 |   "version" : VERSION,
 91 |   "expires" : EXPIRES,
 92 |   "keys" : {
 93 |     KEYID : KEY
 94 |     , ...
 95 |   },
 96 |   "roles" : {
 97 |     ROLE : {
 98 |       "keyids" : [ KEYID, ... ] ,
 99 |       "threshold" : THRESHOLD }
100 |       , ...
101 |     }
102 | }
103 | 
104 | 105 | New format of the signed portion of the Root file: 106 | 107 |
108 | {
109 |   "_type" : "root",
110 |   "consistent_snapshot": CONSISTENT_SNAPSHOT,
111 |   "version" : VERSION,
112 |   "expires" : EXPIRES,
113 |   "keys" : {
114 |     KEYID : KEY
115 |     , ...
116 |   },
117 |   "roles" : {
118 |     ROLE : {
119 |       "keyids" : [ KEYID, ... ] ,
120 |       "threshold" : THRESHOLD }
121 |       , ...
122 |     }
123 | }
124 | 
125 | 126 | # Security Analysis 127 | 128 | This TAP does not detract from existing security guarantees because it does not 129 | propose architectural changes to the specification. 130 | 131 | # Backwards Compatibility 132 | 133 | This TAP introduces a backwards incompatibility, namely the removal 134 | of the *compressed_algorithms* attribute. 135 | 136 | # Augmented Reference Implementation 137 | 138 | Pull request [#485](https://github.com/theupdateframework/python-tuf/pull/485) removes native support for compressed metadata. 139 | 140 | # Copyright 141 | 142 | This document has been placed in the public domain. 143 | -------------------------------------------------------------------------------- /tap11.md: -------------------------------------------------------------------------------- 1 | * TAP: 11 2 | * Title: Using POUFs for Interoperability 3 | * Version: 1 4 | * Last-Modified: 17-Jul-2020 5 | * Author: Marina Moore, Santiago Torres, Trishank Kuppusamy, Sebastien Awwad, Justin Cappos 6 | * Status: Accepted 7 | * Content-Type: text/markdown 8 | * Created: 9-November-2018 9 | 10 | # Abstract 11 | 12 | This TAP describes a mechanism called a POUF (Protocol, Operations, Usage, and Format) that can be used to standardize implementation formats for systems using TUF. If clients and servers implement the same POUF, they will have the same data format and operations and thus be able to interoperate. 13 | 14 | The POUF format was inspired by [TAPs](https://github.com/theupdateframework/taps/blob/master/tap1.md) and Uptane [POUFs](https://github.com/uptane/POUFs). 15 | 16 | # Motivation 17 | 18 | The designers of TUF made a conscious choice not to specify a wireline format. 19 | This was done to accommodate adopters who needed to maintain their existing wireline format due to interactions with other technologies, the requirements of legacy systems, or other unique design parameters. 20 | For example, it is possible to implement TUF with all of the data stored in JSON files, XML files, or a binary format. 21 | The choice of file type or wireline format does not impact the ability to correctly respond to key compromise, so long as the TUF specification is followed. 22 | However, without a shared wireline format, differing TUF implementations will not be able to interoperate. 23 | 24 | Even though different wireline formats are expressly permitted, it would be helpful to have a mechanism that allows different implementations of TUF to work together if they elect to do so. 25 | The mechanism described in this TAP, a POUF, is a publicly implementable and compatible wireline format. 26 | In addition to wireline format, POUFs contain details of any design decisions including additional metadata fields, encodings, and encryption that affect the operation of the implementation on the wire. POUFs allow different TUF implementations with the same POUF to interoperate. 27 | 28 | # Rationale 29 | 30 | A POUF is needed if a TUF implementation needs to communicate with other implementations. 31 | The POUF will include all definitions necessary to create a compatible implementation, including all of the data types and metadata files. 32 | To facilitate the use of POUFs, we describe a standard format for the information to be provided in a POUF. 33 | 34 | Once created, POUFs should be stored publicly to be available to any TUF implementer who wants to interoperate with that POUF. 35 | The TAP repository will contain links to POUFs to allow them to be centrally accessed. 36 | The TUF maintainers do not verify the accuracy or security of POUFs, and so only host links to POUFs. 37 | 38 | We additionally describe an optional security audit process for POUFs that provides some additional oversight to ensure that a POUF does not violate the security guarantees of TUF. 39 | This audit is not required as security of implementation details is still left to implementers, but it provides a process for those interested in additional auditing. 40 | 41 | # Specification 42 | 43 | To ensure that the formats and design decisions described in a POUF work in practice, a POUF should be based on a working TUF implementation. 44 | The implementation may be open or closed source, but the author of the POUF should attest that the POUF has been implemented and that it provides a complete picture of a TUF implementation. 45 | This ensures that the POUF includes all elements for interoperability with the implementation. 46 | 47 | The current status of a POUF will be described with a status of Draft, In Use, or Obsolete. 48 | A draft POUF is still in progress, an in use POUF is a completed POUF, and an obsolete POUF is outdated, but maintained for backwards compatibility. 49 | These statuses are maintained by the POUF author and included in the header of the POUF. 50 | They allow POUFs in all stages to be made available while clarifying which are ready to be implemented. 51 | 52 | POUFs may be changed over time to account for changes to the TUF specification, updates to protocols, or other design changes. 53 | To indicate that a change has occurred, new version numbers should be assigned to the POUF. The version number will be stored in the POUF header as described in [POUF Format](#pouf-format). 54 | In order for a POUF implementer to know if their implementation needs to be updated, any changes that make a POUF not backwards compatible should result in a new version number. 55 | The format and management of version numbers is left to the POUF author, but standard formats like Semantic Versioning (https://semver.org/) are recommended for clarity and consistency with TUF. In addition, POUF authors may refer to how TUF manages updates to ensure that non backwards compatible POUFs do not interfere with TUF communication. 56 | 57 | When changes to a POUF are not backwards compatible, the POUF author can deal with this in a number of ways. 58 | If the breaking change is due to a breaking change to the TUF specification, the update can be handled through the [breaking changes process for TUF](https://github.com/theupdateframework/taps/pull/107). 59 | Alternatively, if a breaking change is made to a POUF separate from a corresponding breaking change in the TUF specification, the POUF author should determine how to disseminate this update to clients and repositories that implement the POUF. 60 | If these breaking changes are anticipated at the time of POUF creation, the author may choose to include the POUF version number in Root metadata and require that clients check this POUF version number for compatibility using a similar process to how TUF handles breaking changes. 61 | Alternatively, a POUF author could create a new POUF that includes the breaking changes. 62 | All of these decisions about breaking changes to POUFs are left to the POUF author to allow for flexibility. 63 | 64 | Not all TUF implementations will use the same wireline format, so there will be multiple POUFs for TUF. 65 | While a given POUF will allow all implementations that adopt it to work together, POUFs may or may not be able to interoperate with each other. 66 | For example, implementers a and b may implement POUF p1. 67 | This means that a and b will be able to interoperate, but they will not necessarily be able to interoperate with implementers of POUF p2. 68 | It is important that implementations list in their documentation the POUF(s) that are supported as well as the version numbers for these POUF(s) so that other implementers looking to interoperate may refer to the relevant POUF. 69 | 70 | To ensure that a POUF follows the TUF specification and that it does not introduce new security issues, we recommend a security audit for POUFs as described in [Security Audit](#security-audit). 71 | In addition to checking the POUF against the specification, this audit ensures that the encoding method or design decisions do not introduce ambiguity or an insecure implementation. 72 | The security audit does not guarantee security, but provides some oversight. 73 | 74 | ## POUF Storage 75 | 76 | If a POUF author wants their POUF to be publicly accessed and reviewed, it should be stored in a public location that can be accessed by other TUF implementers. 77 | In addition to storing the current POUF, the author may maintain old versions of the POUF to allow existing implementations to continue to refer to them. 78 | Old versions will have a unique version number in the header as described in [POUF Format](#pouf-format), and may additionally be named according to the POUF version. 79 | For example a POUF repository may contain two documents, POUFNAME-1.md and POUFNAME-2.md, that contain version 1 and 2 of the POUF respectively. 80 | 81 | A link to a public POUF can be added to the TAP repository through the pull request process. 82 | A document in the TAP repository at POUFs/POUF-links will contain a list of POUF numbers and a link to the associated POUF. 83 | The POUF number is assigned when the POUF link is added to the repository. 84 | POUF links may be a link to the POUF document, or a link to a repository or other location that contains the POUF. 85 | The latter allows POUF authors to maintain old versions of the POUF all in the same location. 86 | 87 | ## POUF Format 88 | 89 | POUFs contain some metadata about the POUF, including the POUF number, POUF version, TUF version, and authors, followed by the Protocol, Operations, Usage, and Formats sections. 90 | Together, the sections of a POUF should include enough information to create an interoperable TUF implementation. 91 | 92 | At a minimum, a POUF shall contain the following sections: 93 | * Header: An RFC 822 style header preamble containing: 94 | * POUF: number 95 | * Title: 96 | * Version: 97 | * Last-Modified: 98 | * Author: optional list of authors' real names and email addresses 99 | * Status: Draft / In Use / Obsolete 100 | * TUF Version(s) Implemented: the release version of the TUF specification versions covered by the POUF 101 | * Implementation Version(s) Covered: release version information of the implementation versions covered by this Version of the POUF 102 | * Content-Type: text/markdown 103 | * Created: date created on, in dd-mmm-yyyy format 104 | * Abstract: Description of the POUF including an overview of design decisions. If the POUF version has been updated, a summary of high-level changes to the POUF should be described here. 105 | * Protocol: The protocol section describes the networking operations of the implementation. This includes the protocol used to transmit data, the location and filenames of any hosted files, and a Message Handler Table. The Message Handler Table will list all messages transmitted by the implementation. Each entry in the Message Handler Table will include the sender, receiver, data, and expected response. All messages in this table must be implemented by anyone using the POUF. 106 | * Operations: The operations section contains a description of any design elements or features that differ from the TUF specification. This section will describe any optional or additional features that are required for compatibility. The format of data does not need to be described here. 107 | * Usage: The usage section contains an overview of how data is managed by the implementation. This includes key management, key rotation, server setup, supply chain security, and device registration. 108 | * Formats: This section contains details about the encoding and format of TUF data as transmitted. It should describe how data is formatted on the repository and client. Data that is not transmitted does not need to be included in a POUF. Descriptions of data formats should include the order of fields to allow for a bitwise identical implementation. This section may include common formats used by all metadata files to avoid redundancy. At a minimum, the format of the following files should be described: 109 | * root 110 | * snapshot 111 | * targets 112 | * delegated targets 113 | * timestamp 114 | 115 | Note that though delegated targets may not be used by an implementation, it is a good idea to set up a format for them. 116 | This will allow the POUF to be used by implementations that do use delegated targets. 117 | 118 | If mirrors are supported by the POUF, their format should be described here. Information about how mirrors are used may be included in the Operations section of the POUF. 119 | 120 | The canonical json description currently in the TUF specification (under "Document Formats") provides an example of the type definitions required for the Formats section of a POUF. 121 | * Security Audit: The third party security audit as described in [Security Audit](#security-audit). 122 | * Version History: For versions beyond the initial release this should be a list of changes introduced in each new version of the POUF. This section could also map POUF versions to releases of the implementation. 123 | 124 | ## Security Audit 125 | 126 | An optional security audit checks that a POUF is a valid implementation of TUF and checks for security flaws and vulnerabilities. 127 | For most POUFs, this audit will consist of ensuring that all fields correspond to those in the TUF specification. 128 | In addition, any libraries or added features should also be audited to be sure they do not add security flaws. 129 | 130 | To ensure the audit is available to all implementers of a POUF, it should be written up and posted with the POUF. 131 | A public posting of the audit allows implementers to make informed decisions about what POUF they wish to use. 132 | The audit will state that the POUF is compliant to the current version of the TUF specification and note any relevant security concerns. 133 | It should be done by a third party (someone who did not participate in the writing or implementation of the POUF). 134 | Like any audit this process ensures that POUFs have been reviewed by a third party, but does not guarantee security of an implementation. 135 | 136 | If security issues are found outside the security audit, they should be promptly reported to both the POUF author and a TUF contributor. 137 | By initially reporting the issue privately, it can be addressed without leaving existing implementations vulnerable to a publicly posted attack. 138 | Once resolved, the issue should be added to the security audit for the POUF. 139 | 140 | The canonical json wireline format that is currently included in the TUF specification has been audited as part of TUF security audits. 141 | As such, additional auditing of this format is not necessary. 142 | 143 | # Security Analysis 144 | 145 | This TAP does not affect the security of TUF. 146 | An implementation that uses a POUF will be able to refer to the security audit for that POUF for security analysis. 147 | Implementations using POUFs are still responsible for ensuring that they follow good secure programming practices and properly implement the TUF specification. 148 | 149 | # Backwards Compatibility 150 | 151 | This TAP is backwards compatible as existing implementations may continue to use the canonical json in the original TUF specification. 152 | 153 | # Augmented Reference Implementation 154 | 155 | N/A 156 | 157 | # Copyright 158 | 159 | This document has been placed in the public domain. 160 | -------------------------------------------------------------------------------- /tap12.md: -------------------------------------------------------------------------------- 1 | * TAP: 12 2 | * Title: Improving keyid flexibility 3 | * Version: 1.0.0 4 | * Last-Modified: 09-04-2020 5 | * Author: Marina Moore 6 | * Status: Accepted 7 | * Content-Type: markdown 8 | * Created: 18-03-2020 9 | * TUF-Version: 1.1.0 10 | * Post-History: 25-03-2020 11 | 12 | # Abstract 13 | 14 | Keyids are used in TUF metadata as shorthand references to identify keys. They 15 | are used in place of keys in metadata to assign keys to roles and to identify 16 | them in signature headers. The TUF specification requires that every keyid used 17 | in TUF metadata be calculated using a SHA2-256 hash of the public key it 18 | represents. This algorithm is used elsewhere in the TUF specification and so 19 | provides an existing method for calculating unique keyids. Yet, such a rigid 20 | requirement does not allow for the deprecation of SHA2-256. A security flaw in 21 | SHA2-256 may be discovered, so TUF implementers may choose to deprecate this 22 | algorithm. If SHA2-256 is deprecated in a TUF implementation, it should no longer be used to 23 | calculate keyids. Therefore TUF should allow more flexibility in how keyids are 24 | determined. To this end, this TAP proposes a change to the TUF specification 25 | that would remove the requirement that all keyids be calculated using SHA2-256. 26 | Instead, the specification will allow metadata owners to use any method for 27 | calculating keyids as long as each one is unique within the metadata file in 28 | which it is defined to ensure a fast lookup of trusted signing keys. This 29 | change will allow for the deprecation of SHA2-256 and will give metadata owners 30 | flexibility in how they determine keyids. 31 | 32 | 33 | # Motivation 34 | 35 | Currently, the TUF specification requires that keyids must be the SHA2-256 hash 36 | of the public key they represent. This algorithm ensures that keyids are unique 37 | within a metadata file (and indeed, throughout the implementation) and creates a 38 | short, space-saving representation. SHA2-256 also offers a number of secure 39 | hashing properties, though these are not necessary for these purposes. In this 40 | case SHA2-256 is simply a way to calculate a unique identifier employing an 41 | algorithm that is already in use by the system. 42 | 43 | The specification sets the following requirements for keyid calculation: 44 | 1. "The KEYID of a key is the hexdigest of the SHA-256 hash of the canonical JSON form of the key." 45 | 2. "Clients MUST calculate each KEYID to verify this is correct for the associated key." 46 | 3. "Clients MUST ensure that for any KEYID...only one unique key has that KEYID." 47 | 48 | ## Problems with this requirement 49 | Mandating that keyids be calculated using SHA2-256 has created a number of issues 50 | for some implementations, such as: 51 | * Lack of consistency in implementations that use other hash algorithms for 52 | calculating file hashes and would prefer not to introduce SHA2-256 for this 53 | one instance. For example, the PEP 458 implementation 54 | will use the BLAKE2 hashing algorithm throughout the implementation. 55 | * Incompatibility with some smart cards and PGP implementations that have their 56 | own way of calculating keyids. 57 | * Inability to adapt if SHA2-256 should be deprecated. In such a case, metadata 58 | owners may decide that maintaining a deprecated algorithm for use in keyid 59 | calculation does not make sense. 60 | * Space concerns may require even shorter hashes than those SHA2-256 can generate, 61 | such as an index. 62 | In these and other cases, TUF should provide a metadata file owner with the 63 | flexibility to use keyids that are not calculated using SHA2-256. 64 | 65 | # Rationale 66 | 67 | TUF uses keyids as shorthand references to identify which keys are trusted to 68 | sign each metadata file. As they eliminate the need to list the full key every 69 | time, they take up less space in metadata signatures than the actual signing 70 | key, reducing bandwidth usage and download times. 71 | 72 | The most important quality of keyids used in TUF is their uniqueness. To be 73 | effective identifiers, all keyids defined within a metadata file must be unique. 74 | For example, a root file that delegates trust to root, snapshot, timestamp, and 75 | top-level targets should provide unique keyids for each key trusted to sign 76 | metadata for these roles. By doing so, a client may check metadata signatures 77 | in O(1) time by looking up the proper key for verification. 78 | 79 | Failing to provide unique keyids can have consequences for both functionality 80 | and security. These are a few attacks that are possible when keyids are not unique: 81 | * **Invalid Signature Verification**: A client may lookup the wrong key to use 82 | in signature verification leading to an invalid signature verification error, 83 | even if the signature used the correct key. 84 | * **Keyid collision**: If root metadata listed the same keyid K for different 85 | snapshot and root keys, an attacker with access to the snapshot key would also 86 | be able to sign valid root metadata. Using the snapshot key to sign root 87 | metadata, the attacker could then list the signature in the header with K. A 88 | client verifying the signature of this root metadata file, would use K to 89 | lookup a key trusted to sign root, and would find the snapshot key and 90 | continue the update with the malicious root metadata. To prevent this 91 | privilege escalation attack, metadata file owners should ensure that 92 | every keyid is associated with a single key in each metadata file. 93 | One attack that does not need to be considered is a hash collision. Though an 94 | attacker who is able to exploit a hash collision against the function used to 95 | calculate the keyid will be able to identify another key that hashes to the 96 | value of the keyid, the client will only use a key that is listed in the 97 | metadata. The attacker would not be able to put a malicious key into the 98 | metadata without the metadata signing key, so a hash collision cannot be used 99 | to maliciously sign files. 100 | 101 | # Specification 102 | 103 | With just a few minor changes to the current TUF specification process, we can 104 | remove the requirement that keyids must be calculated using SHA2-256. First, the 105 | specification wording should be updated to allow the metadata owner to calculate 106 | keyids using any method that produces a unique identifier within the metadata 107 | file. This means replacing requirements 1 and 2 above with a description of 108 | required keyid properties, ie “The KEYID is an identifier for the key that is 109 | determined by the metadata owner and MUST be unique within the delegating metadata file (either root or 110 | delegating targets metadata).” Once this keyid is determined by the metadata 111 | owner using their chosen method, it will be listed in the delegating metadata 112 | file and in all signatures that use the corresponding key. When parsing metadata 113 | signatures, the client would use the keyid(s) listed in the signature header to 114 | find the key(s) that are trusted for that role in the delegating metadata. This 115 | should be described in the specification by replacing requirement 3 above with 116 | “Clients MUST use the keyids from the delegating role to look up trusted signing 117 | keys to verify signatures.” To ensure that a client does not use the same key 118 | to verify a signature more than once, they must additionally check that all keys 119 | applied to a signature threshold are unique. So, the specification should 120 | additionally require that "Clients MUST use each key only once during a given 121 | signature verification." During this de-duplication check, the client should use 122 | a standardized representation for keys, like the [modulus and exponent for RSA](https://cryptography.io/en/latest/hazmat/primitives/asymmetric/rsa/#numbers) 123 | or the [point and curve for ECC](https://cryptography.io/en/latest/hazmat/primitives/asymmetric/ec/#cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicNumbers). 124 | All metadata definitions would remain the same, but 125 | the client’s verification process would track keyids within each metadata file 126 | instead of globally. 127 | 128 | In order for TUF clients to adhere to these specification changes, they may have 129 | to change the way they store and process keyids. Clients will use the keyids 130 | from a metadata file only for all delegations defined in that metadata file. So 131 | if a targets metadata file T delegates to A and B, the client should verify the 132 | signatures of A and B using the trusted keyids from T. When verifying 133 | signatures, clients should try all signatures that match their trusted keyid(s). 134 | If T trusts keyid K to sign A’s metadata, the client should check all 135 | signatures in A that list a keyid of K. This means that if another metadata file 136 | M delegates to A, it would be able to use the same keyid with a different key. 137 | However, clients must ensure that duplicate keys are not applied to the same 138 | signature threshold. To do so, they must additionally keep track of the keys 139 | used to verify a signature using a standardized representation as discussed above. Once 140 | the signatures for A and B have been checked, 141 | the client no longer needs to store the keyid mapping listed in T. During the 142 | preorder depth-first search of targets metadata, the keyids from each targets 143 | metadata file should be used in only that stage of the depth-first search. 144 | 145 | These changes to the specification allow the repository to use any scheme to 146 | assign keyids (not just SHA2-256) without needing to communicate it to clients. By making this 147 | scheme independent of the client implementation, root and targets metadata may 148 | use different methods to determine keyids, especially if they are managed by 149 | different people (ie TAP 5). In addition, the repository may update the scheme 150 | at any time to deprecate a hash algorithm or change to a different keyid 151 | calculation method. 152 | 153 | ## Keyid Deprecation 154 | With the proposed specification changes, the method used to determine keyids 155 | is not only more flexible, but it may be deprecated using the following process 156 | for each key D and keyid K in the root or delegating targets metadata file: 157 | * The owner of the metadata file determines a new keyid L for D using the new method. 158 | * In the next version of the metadata file, the metadata owner replaces K with L 159 | in the keyid definition for D. 160 | * Any files previously signed by D should list L as the keyid instead of K. 161 | These files do not need to be resigned as only the signature header will be updated. 162 | Once this process is complete, the metadata owner is using a new method to 163 | determine the keyids used by that metadata file. 164 | 165 | As keyid deprecation is executed, it is important that keyids within each 166 | metadata file remain unique. Metadata owners should only publish metadata that 167 | contains a unique keyid to key mapping. 168 | 169 | ## Implications for complex delegation trees 170 | Although keyids need to be unique within each metadata file, they do not need to 171 | be unique for each delegated role. It is possible for different keyids to 172 | represent the same key in different metadata files, even if both metadata files 173 | delegate to the same role. Consider two delegated targets metadata files A and B 174 | that delegate to the same targets metadata file C. If A delegates to C with 175 | key D with keyid K and B delegates to C with key D with keyid L, the signature 176 | header of C will contain the following: 177 | ``` 178 | { 179 | "sigs": [ 180 | { 181 | "keyid": "K", 182 | "sig": "abcd..." 183 | }, 184 | { 185 | "keyid": "L", 186 | "sig": "abcd..." 187 | }, 188 | ... 189 | ], 190 | ... 191 | } 192 | ``` 193 | These delegations can be processed during the preorder depth-first search of 194 | targets metadata as follows: 195 | * When the search reaches A, it will look for a signature with a keyid of K in C. 196 | If it finds this and validates it, the search will continue if a threshold of 197 | signatures has not been reached. 198 | * When the search reaches B, it will look for a signature with a keyid of L in C. 199 | If it finds this and validates it, the search will continue if a threshold of 200 | signatures has not been reached. 201 | Once the search is complete, if a threshold of signatures is reached the 202 | metadata in C will be used to continue the update process. Therefore, K and L 203 | may be used as keyids for D in different metadata files. As clients store keyids 204 | only for use in the current delegation, this should not require a change to the 205 | client process described in this document. 206 | 207 | In this case, the same key D is used to verify C twice, once when A delegates to 208 | C and once when B delegates to C. As the key is only used once during each 209 | delegation, this does not violate the client verification of key uniqueness 210 | described in this TAP. If the keyids L and K were both used in the same 211 | delegation (say A delegating to C), then these signatures would only contribute 212 | a single valid signature to the threshold due to the client verification. 213 | 214 | It is also possible for the same keyid to represent different keys in different 215 | metadata files. Consider a targets metadata file A that delegates to C with key 216 | D and keyid K and a targets metadata file B that delegates to C with key E and 217 | keyid K. The signature header of C will contain the following: 218 | ``` 219 | { 220 | "sigs": [ 221 | { 222 | "keyid": "K", 223 | "sig": "abcd..." 224 | }, 225 | { 226 | "keyid": "K", 227 | "sig": "efgh..." 228 | }, 229 | ... 230 | ], 231 | ... 232 | } 233 | ``` 234 | 235 | During the depth-first search of targets metadata, the client will process these 236 | delegations as follows: 237 | * When the search reaches A, it will look for a signature with a keyid of K in 238 | C. It will discover two signatures with the given keyid, and will check each 239 | using the key D. If either passes the verification, the search will continue 240 | if a threshold of signatures has not been reached. 241 | * When the search reaches B, it will look for a signature with a keyid of K in 242 | C. It will discover two signatures with the given keyid, and will check each 243 | using the key E. If either passes the verification, the search will continue 244 | if a threshold of signatures has not been reached. 245 | Using this process, the same keyid may be used across metadata files without 246 | being associated with the same key. 247 | 248 | In both of these cases, the client must ensure that signatures using the same 249 | key are not applied to the same threshold. To do so, clients must keep track 250 | of the keys used during signature verification to ensure that there is a 251 | threshold of unique keys that have signed the metadata. 252 | 253 | # Security Analysis 254 | 255 | TUF clients only trust keys that are defined in signed metadata files. For this 256 | reason, the method of calculating keyids does not allow an attacker to add 257 | new trusted keys to the system. However, a bad keyid scheme could allow a 258 | privilege escalation in which the client verifies one metadata file with a 259 | key from a role not trusted to sign that metadata file. This proposal prevents 260 | privilege escalation attacks by requiring that metadata owners use unique keyids 261 | within each metadata file, as described in the rationale. 262 | 263 | # Backwards Compatibility 264 | 265 | Metadata files that are generated using SHA2-256 will be compatible with clients 266 | that implement this change. However, clients that continue to check that 267 | keyids are generated using SHA2-256 will not be compatible with metadata that 268 | uses a different method for calculating keyids. 269 | 270 | For backwards compatibility, metadata owners may choose to continue to use 271 | SHA2-256 to calculate keyids. 272 | 273 | # Augmented Reference Implementation 274 | 275 | [python-tuf 1.0](https://github.com/theupdateframework/python-tuf/releases/tag/v1.0.0) does not calculate keyids using the hash algorithm. 276 | 277 | # Copyright 278 | 279 | This document has been placed in the public domain. 280 | -------------------------------------------------------------------------------- /tap13.md: -------------------------------------------------------------------------------- 1 | * TAP: 13 2 | * Title: User Selection of the Top-Level Targets Files Through Mapping Metadata 3 | * Version: 1 4 | * Last-Modified: 02-Nov-2021 5 | * Author: Justin Cappos, Joshua Lock, Marina Moore, Lukas Pühringer 6 | * Status: Draft 7 | * Content-Type: text/markdown 8 | * Requires: TAP 4 9 | * Created: 29-May-2020 10 | 11 | # Abstract 12 | 13 | This TAP discusses a means by which different users of the same repository 14 | may elect to use different, repository-hosted, top-level targets metadata. This 15 | effectively enables different namespaces to exist on a repository which a client 16 | may choose to trust -- or not -- in a granular fashion, and also provides 17 | additional resilience to attack in the case that the root keys on the 18 | repository are compromised. 19 | 20 | 21 | 22 | # Motivation 23 | 24 | Currently if a user trusts a TUF repository, a compromise of the targets role 25 | for that repository enables an attacker to install arbitrary malicious software. 26 | The targets role on the repository is responsible for delegating to the correct 27 | key for each delegated targets, and so may also arbitrarily replace these keys. 28 | A third party that controls 29 | a delegated targets role gives their keys to the delegating role on the 30 | repository, then has to trust that the repository will correctly list the 31 | trusted keys for their role. In some cases, the user may wish to reduce trust 32 | in the repository by maintaining control of key distribution. 33 | 34 | For users of some public repositories, the repository is considered an untrusted 35 | distribution mechanism, and should not be trusted with this key distribution. 36 | For these repositories, the owner of a delegated targets role needs a mechanism 37 | to ensure that their users can define and pin keys. 38 | 39 | To allow for safer use of these untrusted repositories, we propose adding 40 | namespaces to TUF repositories which enable explicit trust decisions. In this 41 | mode, if Alice and Bob both use repository X and ask for package foo, they may 42 | get different results based on their trusted namespaces. 43 | In summary; this proposal enables clients to restrict the targets roles they consume 44 | to filtered views of the repository. 45 | 46 | These different views could be defined by either different users on the 47 | repository, made available by the repository administrator, or be created by 48 | some other third party. Some likely uses include: 49 | * **Limiting packages on a repository to those that have been signed by their 50 | developer.** For example, in the proposed 51 | [PyPI Maximum Security Model](https://www.python.org/dev/peps/pep-0480/), 52 | packages that are only signed by the repository are listed under the 'unclaimed' 53 | targets role, while packages that are signed by developers are delegated 54 | from the 'claimed' targets role. A user may wish to restrict packages to those 55 | that have been end-to-end signed, and so only use packages delegated from 56 | 'claimed'. 57 | * **Curating a list of verified packages.** A company may curate a subset of 58 | packages available on a container registry that have been validated for use 59 | by their customers. This curated list may include packages that the company 60 | signs, as well as trusted third-party dependencies. They may then 61 | distribute this curated list to users, who want to ensure that only 62 | validated packages are installed. 63 | 64 | There are several reasons why it may be important to let Alice and Bob's view of 65 | the repository differ. 66 | 67 | First, Alice and Bob may each curate different lists of packages that they 68 | trust. For example, the security team at Alice's company has only blessed 69 | specific packages and Alice wishes to install only those packages. Every other 70 | user clearly should not be subject to those constraints. 71 | 72 | Second, Alice may be concerned that a full repository compromise may include 73 | the root role. Since the root role in TUF indicates the top-level targets' 74 | role key, this compromise can enable the attacker full control of Alice's 75 | namespace. Alice may want to require that the security team at her company 76 | still be used to decide which packages to trust. 77 | 78 | Finally, in fact, Alice's company may have dictated that references to 79 | 'foo' should all (transparently) refer to a specific in-house 80 | version, which may not match the result of 81 | resolving foo using the repository's top-level targets metadata. 82 | Instead foo should refer to the name that is resolved using Alice’s 83 | company’s targets metadata file as the top-level targets metadata file. This may 84 | also enable Alice to install software which is available on the repository 85 | but would not be trusted by other users. 86 | 87 | Note that in all of the above cases, Alice and Bob still want to use the 88 | repository as a means to coordinate and obtain new versions of targets 89 | metadata. They however 1) want control of what packages would be installed 90 | and 2) want to limit the damage caused by a root key compromise on the 91 | repository. 92 | 93 | # Rationale 94 | 95 | We introduce this TAP because the alternative is slightly onerous. One could 96 | technically achieve the first and second use cases (different curated lists of 97 | packages and additional protection against a compromise of the repository’s 98 | root key) by using delegations to multiple repositories. The way in which this 99 | would work would be to have the security team at Alice's company run their 100 | own repository and for Alice to use a mapping [TAP 4](tap4.md) that indicates 101 | that both the security team and the original repository must be trusted for an 102 | installation to happen. In this way, only software blessed by the security team 103 | may be installed. 104 | 105 | However, this does not support the final use case above of transparently 106 | referring to an in-house version. The reason is that 107 | the original repository must also indicate that software is trustworthy, which it 108 | would not in this case. This TAP allows the user to override (i.e., ignore) the 109 | top-level targets metadata. The repository's separate namespace will not 110 | match with Alice's in this case. 111 | 112 | # Specification 113 | 114 | In order to support this situation, we propose a mapping 115 | metadata to enable the name and key(s) for a targets metadata file to be specified. 116 | This targets metadata file will be uploaded to the repository and will be used as though 117 | it is the top-level targets metadata file by the client instead of the top-level targets 118 | metadata file listed in the repository's root metadata. As is true in all TUF repositories, 119 | all targets metadata files are listed in the snapshot file and benefit from the usual 120 | rollback and similar protections provided. 121 | 122 | Note that both the name and the key MUST be specified. If the name 123 | were permitted to be specified without the key, then the repository 124 | would be trusted to serve the correct file, without any offline key attesting 125 | to which keys indicate the targets role. The resulting metadata will look like: 126 | 127 | ``` 128 | { 129 | "targets_rolename": ROLENAME, 130 | "threshold": THRESHOLD, 131 | "keys":{ 132 | KEYID : KEY, 133 | ... 134 | } 135 | } 136 | ``` 137 | 138 | As such, we add to the [Mechanisms that Assigns Targets to Repositories](https://github.com/theupdateframework/taps/blob/master/tap4.md#mechanism-that-assigns-targets-to-repositories) 139 | support for a reference to the targets metadata file in an identical way to the 140 | root file's reference in the [TUF specification](https://github.com/theupdateframework/specification/blob/master/tuf-spec.md#4-document-formats). 141 | However, additionally, the file name must be specified as this is no longer 142 | targets.json. 143 | 144 | Note that the TUF specification's discussions about metadata storage, writing, 145 | and retrieval are not changed by this TAP. The description about how to 146 | (optionally) write consistent snapshots is not changed by this TAP. Consistent 147 | snapshots already require versioned metadata to be available for all targets metadata 148 | files. All targets metadata files (top-level and otherwise) are also stored in the 149 | same METAPATH location listed in snapshot.json. 150 | 151 | The changes in the client application workflow are fairly minor from this 152 | TAP. Steps 4.0 and 4.4.0 should refer to the specified targets' metadata file instead 153 | of the top-level targets metadata file. Additionally, instead of verifying the targets metadata 154 | file using the key in the root metadata in step 4.0, verification must use the 155 | keys listed in the mapping metadata. 156 | 157 | There likely also needs to be a clarity pass throughout to make this potential 158 | use mode clearer in the specification. 159 | 160 | From an operational standpoint, a lost targets key for a delegated targets role could have been 161 | remedied before by the repository but this no longer works in every case. For example, 162 | previously if the repository delegated to a targets role from the top-level targets role, that 163 | file could be updated by the top-level targets role if Alice’s key changed or was lost. 164 | However, as the repository’s root role is no longer trusted to provide top-level targets keys 165 | and different clients may have different top-level targets keys, any clients using this 166 | TAP must take more care. Thus, one should take into account the operational difficultly to touch 167 | clients in the case of key loss or compromise for the top-level targets metadata file. If it is 168 | operationally difficult to touch the clients, then the client may perhaps use a threshold of 169 | offline keys before delegating to a developer’s key. [TAP 8](tap8.md) also provides support for 170 | cases where the key needs to be rotated or changed and the key is still accessible to the developer. 171 | 172 | ## Interaction with TAP 4 173 | 174 | If a client is using TAP 4 to provide mapping metadata to multiple repositories, 175 | they MAY provide a TAP 13 targets mapping for each repository or group of repositories. 176 | An optional `targets_mappings` field will be added to TAP 4 to provide this mapping 177 | when TAP 13 is used. The mappings will be resolved in order, so the first mapping 178 | will have higher priority than the second, and so on. This field will be resolved 179 | after the TAP 4 `mapping` field and will contain: 180 | 181 | ``` 182 | "targets_mappings": [ 183 | { 184 | "repositories": [REPOSITORY_NAME, ...], 185 | "targets_rolename": ROLENAME, 186 | "threshold": THRESHOLD, 187 | "keys":{ 188 | KEYID : KEY, 189 | ... 190 | } 191 | }, 192 | ... 193 | ] 194 | ``` 195 | 196 | Where `REPOSITORY_NAME` is the name of the target repository defined in TAP 4, 197 | and the other fields are as described above. 198 | 199 | If a client is not using TAP 4, the targets mapping may instead be in a separate 200 | metadata file as described above. 201 | 202 | # Security Analysis 203 | 204 | Our overall belief is that this is a security positive change to TUF. 205 | The added complexity from this change is fairly small. The mapping metadata 206 | itself already exists in TUF and this TAP merely makes a small addition to 207 | parameterize the top-level targets role. We feel that implementation errors 208 | with adding this TAP are unlikely to occur. However, the ability to better 209 | control trust should help users to better secure important operational use 210 | cases. We are also unaware of plausible scenarios where this feature would 211 | lead to insecurity due to abuse or misconfiguration except the inability to 212 | have the root role rotate the targets key. However, selectively removing this 213 | capability from the root role is the purpose of this TAP. 214 | 215 | # Backwards Compatibility 216 | 217 | This TAP does not require clients that do not support this TAP to update. 218 | Hence, all existing clients may continue to update. As the mapping metadata 219 | is controlled on the client device, this will need to be updated along with the 220 | client implementation. The repository metadata does not change in any way. 221 | 222 | # Augmented Reference Implementation 223 | 224 | [TODO: Point to a branch containing implementation of TAP 13.] 225 | 226 | # Copyright 227 | 228 | This document has been placed in the public domain. 229 | -------------------------------------------------------------------------------- /tap15.md: -------------------------------------------------------------------------------- 1 | * TAP: 15 2 | * Title: Succinct hashed bin delegations 3 | * Version: 1 4 | * Last-Modified: 09-06-2022 5 | * Author: Marina Moore, Lukas Pühringer, Justin Cappos 6 | * Status: Accepted 7 | * Created: 23-06-2020 8 | * TUF-Version: 1.0.0 9 | * Post-History: 10 | 11 | # Abstract 12 | 13 | TUF delegating metadata contains the keyid and path for each 14 | delegation, so when a single metadata file delegates to many others 15 | the delegating metadata’s size increases proportionally to the number of 16 | delegations. Clients must download this large delegating metadata file 17 | when they update any target it delegates to, therefore large 18 | delegating metadata increases the client’s metadata overhead. To 19 | reduce the metadata overhead for targets metadata that contains many 20 | delegations, TUF supports hashed bin delegations. Hashed bin delegations 21 | use a targets role that delegates to ‘bin’ roles, which sign metadata 22 | for the actual target files in the bin. Targets files are distributed to bins using 23 | the hash of the target filename. Using hashed bin delegations, the 24 | delegating metadata only delegates to the bins, and so contain less 25 | data. Thus, hashed bin delegations reduce the client’s metadata 26 | overhead. 27 | 28 | Currently, hashed bin delegations function much like standard TUF 29 | delegations, so the delegating metadata lists the keyid and path for 30 | each bin. In practice, most hashed bin delegations use the same keyid 31 | for each bin and these bins are hashed in a predictable pattern, 32 | stored in files with predictable names, and stored in a common 33 | location. Furthermore the delegating metadata contains duplicate keyid 34 | and path information for each bin. This duplicate information adds to 35 | the metadata overhead without providing useful information to the 36 | client. 37 | 38 | This TAP proposes adding a field to delegating metadata to describe 39 | hashed bin delegations that allows a delegating party to succinctly 40 | describe the bins it will delegate to when the hashed bin delegation 41 | follows a common pattern. 42 | 43 | # Motivation 44 | 45 | This TAP supports the following use case: 46 | 47 | Suppose a single targets metadata file contains a very large number of 48 | target files. The owner of this targets metadata file wishes to reduce 49 | the metadata overhead for clients, and so uses hashed bin delegations 50 | choosing 2,048 as appropriate number of bins. Given that hash bin 51 | delegation does not aim at partitioning trust for different target 52 | files, but to reduce metadata overhead, the delegating metadata will use 53 | the same key and signature threshold for each bin. 54 | 55 | Currently, the delegating metadata would list 2,048 role entries, one 56 | for each bin, containing the same information about the signing key, 57 | signature threshold, terminating property and role name prefix. The only 58 | data that differs between these entries are the bin name suffix, which 59 | is the bin index, and the list of target path hash prefixes served by a 60 | particular bin. The differing data is bolded in the example below. 61 | 62 | This data can be computed by the client, if they have minimal knowledge 63 | about the desired partitioning scheme. Providing this information in a 64 | succinct way will further reduce the metadata overhead. 65 | 66 |

 67 | "delegations": {
 68 |     "keys": {
 69 |         "943efed2eea155f383dfe5ccad12902787b2c7c8d9aef9664ebf9f7202972f7a": {...}
 70 |     },
 71 |     "roles": [
 72 |         {
 73 |             "name": "alice.hbd-000",
 74 |             "keyids": [
 75 |                 "943efed2eea155f383dfe5ccad12902787b2c7c8d9aef9664ebf9f7202972f7a"
 76 |             ],
 77 |             "threshold": 1,
 78 |             "path_hash_prefixes": ["000", "001"],
 79 |             "terminating": false,
 80 |         },
 81 |         {
 82 |             "name": "alice.hbd-001",
 83 |             "keyids": [
 84 |                 "943efed2eea155f383dfe5ccad12902787b2c7c8d9aef9664ebf9f7202972f7a"
 85 |             ],
 86 |             "threshold": 1,
 87 |             "path_hash_prefixes": ["002", "003"],
 88 |             "terminating": false,
 89 |         },
 90 |         {
 91 |             "name": "alice.hbd-7ff",
 92 |             "keyids": [
 93 |                 "943efed2eea155f383dfe5ccad12902787b2c7c8d9aef9664ebf9f7202972f7a"
 94 |             ],
 95 |             "threshold": 1,
 96 |             "path_hash_prefixes": ["ffe", "fff"],
 97 |             "terminating": false,
 98 |         },
 99 |     ],
100 | }
101 | 
102 | 103 | # Rationale 104 | 105 | A succinct description of hash bin delegation in the delegating metadata 106 | can significantly reduce the client's metadata overhead. This is achieved 107 | by listing properties common to all bins only once, and by providing the 108 | necessary information to the client to compute which bin is responsible 109 | for the desired target and how the corresponding bin metadata is named. 110 | As a consequence the size of the delegating metadata remains constant, as 111 | opposed to traditional hash bin delegation, where it grows linearly with 112 | the number of bins. 113 | 114 | For a real-world repository, as described in PEP 458, with 2M target 115 | files distributed over 16K bins, the delegating metadata would grow by 116 | 1.25 MB when using traditional hash bin delegation, and impose a 117 | per-package TUF metadata overhead of 69% on new users (see V10 and V17 in 118 | [PEP 458 - Metadata 119 | Scalability](https://peps.python.org/pep-0458/#metadata-scalability)). 120 | When using succinct hash bin delegation, on the other hand, the 121 | delegating metadata would not grow and the per-package metadata 122 | overhead can be reduced to 9%. 123 | 124 | # Specification 125 | 126 | This TAP extends delegations by adding a `succinct_roles` field 127 | that includes the following: 128 | 129 | ``` 130 | "succinct_roles": { 131 | "keyids": [KEYID, ...], 132 | "threshold": THRESHOLD, 133 | "bit_length": BIT_LENGTH, 134 | "name_prefix": NAME_PREFIX, 135 | } 136 | 137 | ``` 138 | 139 | Where 2^BIT_LENGTH is the number of bins. BIT_LENGTH must be an 140 | integer between 1 and 32 (inclusive). 141 | 142 | KEYID and THRESHOLD have the same definitions as in 143 | previous delegations. 144 | 145 | When a delegation contains this field, it represents delegations to 146 | 2^BIT_LENGTH bins which all use the specified keyids and threshold. All 147 | succinct hashed bin delegations will be non-terminating. If a user 148 | would like succinct delegations to be terminating, they may add the 149 | terminating flag in either the parent delegation or in the individual bins. 150 | 151 | As in the current use of hashed bin delegations, target files will be 152 | distributed to bins based on the SHA2-256 hash of the target path and 153 | a prefix associated with each bin. The 154 | prefix will be computed by the repository and client to 155 | determine which bin each target belongs to. The prefix field will include 156 | the first BIT_LENGTH bits of the hash and will be determined for each 157 | bin i by taking the first BIT_LENGTH bits of i. So for a BIT_LENGTH 158 | of 3, the first bin would include binary 159 | values starting with 000, the second bin would include binary values starting 160 | with 001, the third 010, then 011, 100, 101, 110, 111. 161 | 162 | The rolename of each bin will be determined by the bin number and the 163 | NAME_PREFIX listed in the `name_prefix` field of the delegation, 164 | separated by hyphen (`-`). The name will be structured as 165 | NAME_PREFIX-COUNT where COUNT is a hexadecimal value between 0 and 166 | 2^BIT_LENGTH-1 (inclusive) that represents the bin number. This value will be zero-padded so that all rolenames will be of the same length. 167 | 168 | Only one of `succinct_roles` or `roles` may be specified in a 169 | delegation. If a role A would like to delegate to both `succinct_roles` 170 | S and `roles` R (or to a second succinct role), they may do so through 171 | the use of intermediate delegations. A would create namespaced 172 | delegations to both B and C. B would then delegate to S using 173 | `succinct_roles`, and C would delegate to R using `roles`. An advantage 174 | to this approach is that A may decide which of S or R should be 175 | prioritized for each package through the ordering of the delegations to B and C. 176 | 177 | If a delegation contains a succinct hash delegation, all metadata 178 | files represented by this delegation must exist on the repository, 179 | even if they do not contain any target files or delegations. These bin 180 | files should be uploaded before the metadata that delegates to them. 181 | With the addition of succinct hashed bins, the delegation will contain: 182 | 183 | ``` 184 | { 185 | "keys": { 186 | KEYID: KEY, 187 | ... 188 | }, 189 | ("roles": [ 190 | { 191 | "name": ROLENAME, 192 | "keyids": [KEYID, ...], 193 | "threshold": THRESHOLD, 194 | ("path_hash_prefixes": [HEX_DIGEST, ...], | 195 | "paths": [PATHPATTERN, ...],) 196 | "terminating": TERMINATING, 197 | }, 198 | ..., 199 | ], | 200 | "succinct_roles": { 201 | "keyids": [KEYID, ...], 202 | "threshold": THRESHOLD, 203 | "bit_length": BIT_LENGTH, 204 | "name_prefix": NAME_PREFIX, 205 | },) 206 | } 207 | ``` 208 | 209 | Eventually, the `path_hash_prefixes` field in `roles` MAY be deprecated in favor of `succinct_roles`, but it may be kept for backwards compatibility. 210 | 211 | Using succinct hashed bin delegations, the delegating metadata from the 212 | motivating example will contain: 213 | 214 |

215 | "delegations": {
216 |     "keys": {
217 |         "943efed2eea155f383dfe5ccad12902787b2c7c8d9aef9664ebf9f7202972f7a": {...}
218 |     },
219 |     "succinct_roles": {
220 |         "keyids": [
221 |             "943efed2eea155f383dfe5ccad12902787b2c7c8d9aef9664ebf9f7202972f7a"
222 |         ],
223 |         "threshold": 1,
224 |         "bit_length": 11,
225 |         "name_prefix": "alice.hbd",
226 |     },
227 | }
228 |  
229 | 230 | The associated bins will be named `alice.hbd-000`, `alice.hbd-001`, ... `alice.hbd-7ff`. 231 | 232 | # Security Analysis 233 | 234 | This TAP will not negatively affect the security of TUF. The 235 | succinct_hash_delegations field provides a shorter way to describe an 236 | existing feature when it follows a predictable pattern. If the hashed 237 | bin delegations do not follow this pattern (they use different keys 238 | for different bins, etc), they may instead use the existing hashed bin 239 | mechanism. 240 | 241 | Repositories that use access control for file uploading should take 242 | hashed bin delegations into consideration. Upload access for the name 243 | NAME_PREFIX-\* should have the same permissions as 244 | the delegating role. 245 | 246 | # Backwards Compatibility 247 | 248 | This TAP is not backwards compatible, and will need to be included in 249 | a major version release of the specification. We consider the access 250 | control that must be supported on the repository, as well as 251 | compatibility between the client and the repository. 252 | 253 | The repository must ensure that the correct access control mechanisms 254 | are applied to filenames of the form NAME_PREFIX-\*. As 255 | discussed in the security analysis, this metadata file should only be 256 | uploaded by the delegating role. The repository should handle this 257 | access control before succinct hashed bin delegations are used so that 258 | other uploaders are not able to use the NAME_PREFIX-\* 259 | filename for target files. 260 | 261 | In order for succinct hashed bin delegations to be used, both the 262 | delegation and the client must understand the succinct_hash_delegations 263 | field. Consider a client Bob who wants to download a target J and an 264 | uploader Alice who is responsible for delegating to J. This is what 265 | would happen if one or both of them supports succinct_hash_delegations. 266 | 267 | | Parties that support succinct_hash_delegations | Result | 268 | | --- | --- | 269 | | Neither Alice nor Bob support succinct_hash_delegations | Alice would not use succinct_hash_delegations to delegate to J, and so Bob would be able to download and verify the target using the existing mechanisms. | 270 | | Alice supports succinct_hash_delegations, Bob does not | Alice may use succinct_hash_delegations to delegate to any of her target files, including J. Bob will download metadata that has the succinct_hash_delegations field and will not be able to find the delegation that points to J. | 271 | | Bob supports succinct_hash_delegation, Alice does not | Alice will not use succinct_hash_delegations to delegate to J. Bob will not see this field in the targets metadata, and so will look for the delegation using the existing mechanisms | 272 | | Both Alice and Bob support succinct_hash_delegations | Alice may use succinct_hash_delegations to delegate to her target files, including J. Bob will see the succinct_hash_delegations field in targets metadata and will download the alice.hdb-x bin metadata file that corresponds to J. | 273 | 274 | As you can see, if Alice supports succinct_hash_delegations and Bob 275 | does not, Bob will not be able to verify J. 276 | 277 | # Augmented Reference Implementation 278 | 279 | 280 | https://github.com/theupdateframework/python-tuf/pull/2010 281 | -------------------------------------------------------------------------------- /tap16.md: -------------------------------------------------------------------------------- 1 | * TAP: 16 2 | * Title: Snapshot Merkle Trees 3 | * Version: 0 4 | * Last-Modified: 22/01/2021 5 | * Author: Marina Moore, Justin Cappos 6 | * Type: Standardization 7 | * Status: Draft 8 | * Content-Type: markdown 9 | * Created: 14/09/2020 10 | * +TUF-Version: 11 | * +Post-History: 12 | 13 | # Abstract 14 | 15 | Snapshot metadata for repositories with a high number of targets 16 | metadata files (through significant use of delegations), can become 17 | prohibitively large. Due to the need to download the snapshot file on every 18 | update cycle, very large snapshot metadata files can become a significant 19 | overhead for TUF clients. 20 | 21 | This TAP proposes a method for reducing the size of snapshot metadata a client 22 | must download without significantly weakening the security properties of TUF. 23 | 24 | 25 | # Motivation 26 | 27 | For very large repositories, the snapshot metadata file could get very large. 28 | This snapshot metadata file must be downloaded on every update cycle, and so 29 | could significantly impact the metadata overhead. For example, if a repository 30 | has 50,000,000 targets metadata files, the snapshot metadata will be about 31 | 380,000,000 bytes (https://docs.google.com/spreadsheets/d/18iwWnWvAAZ4In33EWJBgdAWVFE720B_z0eQlB4FpjNc/edit?ts=5ed7d6f4#gid=0). 32 | For this reason, it is necessary to create a more scalable solution for snapshot 33 | metadata that does not significantly impact the security properties of TUF. 34 | 35 | We designed a new approach to snapshot that improves scalability while 36 | achieving similar security properties to the existing snapshot metadata. 37 | Using this new approach, a repository with 50,000,000 targets metadata files 38 | would only require the user to download about 800 bytes of snapshot metadata (https://docs.google.com/spreadsheets/d/18iwWnWvAAZ4In33EWJBgdAWVFE720B_z0eQlB4FpjNc/edit?ts=5ed7d6f4#gid=924553486). 39 | 40 | 41 | # Rationale 42 | 43 | Snapshot metadata provides a consistent view of the repository in order to 44 | protect against mix-and-match attacks and rollback attacks. In order to provide 45 | these protections, snapshot metadata is responsible for keeping track of the 46 | version number of each targets metadata file, ensuring that all targets downloaded are 47 | from the same snapshot, and ensuring that no targets metadata file decreases its version 48 | number (except in the case of fast forward attack recovery). Any new solution 49 | we develop must provide these same protections. 50 | 51 | A snapshot Merkle tree manages version information for each targets metadata 52 | file by including this information in a leaf node for each targets metadata 53 | file. By using a Merkle tree to store these nodes, 54 | this proposal can cryptographically verify that different targets are from the 55 | same snapshot by ensuring that the Merkle tree roots match. Due to the 56 | properties of secure hash functions, any two leaves of a Merkle tree with the 57 | same root are from the same tree. 58 | 59 | In order to prevent rollback attacks between Merkle trees, this proposal 60 | introduces third-party auditors. These auditors are responsible for downloading 61 | all nodes of each Merkle tree to ensure that no version numbers have decreased 62 | between generated trees. This achieves rollback protection without every client 63 | having to store the version information for every targets metadata file. 64 | 65 | # Specification 66 | 67 | This proposal replaces the single snapshot metadata file with a snapshot Merkle 68 | metadata file for each targets metadata file. The repository generates these 69 | snapshot Merkle metadata files by building a Merkle tree using all targets 70 | metadata files and storing the path to each targets metadata file in the 71 | snapshot Merkle metadata. The root of this Merkle tree is stored in timestamp 72 | metadata to allow for client verification. The client uses the path stored in 73 | the snapshot Merkle metadata for a targets metadata file, along 74 | with the root of the Merkle tree, to ensure that metadata is from the given 75 | Merkle tree. The details of these files and procedures are described in 76 | this section. 77 | 78 | ![Diagram of snapshot Merkle tree](merkletap-1.jpg) 79 | 80 | ## Merkle tree generation 81 | 82 | When the repository generates snapshot metadata, instead of putting the version 83 | information for all targets metadata files into a single file, it instead uses the version 84 | information to generate a Merkle tree. Each targets metadata file's version information forms 85 | a leaf of the tree, then these leaves are used to build a Merkle tree. The 86 | internal nodes of a Merkle tree contain the hash of their child nodes. The exact 87 | algorithm for generating this Merkle tree (ie the order of nodes in the hash, 88 | how version information is encoded, etc.), is left to the implementer, but this 89 | algorithm should be documented in a [POUF](https://github.com/theupdateframework/taps/blob/master/tap11.md) 90 | so that implementations can be 91 | compatible and correctly verify Merkle tree data. However, all implementations 92 | should meet the following requirements: 93 | 94 | * Leaf nodes must be unique. A unique identifier of the targets metadata – such as the 95 | filepath, filename, or the hash of the content – must be included in the leaf data to ensure that no two leaf 96 | node hashes are the same. 97 | * The tree must be a Merkle tree. Each internal node must contain a hash that 98 | includes both child nodes. 99 | 100 | A [Merkle prefix tree](https://www.usenix.org/system/files/conference/usenixsecurity15/sec15-paper-melara.pdf) 101 | is suggested as it allows for efficient updates and 102 | non-membership proofs (so that the user can efficiently verify that a particular package 103 | is not in the tree, preventing a DoS attack). 104 | 105 | Once the Merkle tree is generated, the repository must create a snapshot Merkle 106 | metadata file for each targets metadata file. This file must contain the leaf contents and 107 | the path to the root of the Merkle tree. This path must contain the hashes of 108 | nodes needed to reconstruct the tree during verification, including the leaf's 109 | sibling (see diagram). 110 | In addition the path should contain direction information so that the client 111 | will know whether each listed node is a left or right sibling when reconstructing the 112 | tree. 113 | 114 | This information will be included in the following metadata format: 115 | ``` 116 | { “leaf_contents”: {METAFILES}, 117 | “merkle_path”: {INDEX:HASH} 118 | “path_directions”:{INDEX:DIR} 119 | } 120 | ``` 121 | 122 | Where `METAFILES` is the version information as defined for snapshot metadata, 123 | `INDEX` provides the ordering of nodes, `HASH` is the hash of the sibling node, 124 | and `DIR` indicates whether the given node is a left or right sibling. 125 | 126 | In addition, the following optional field will be added to timestamp metadata. 127 | If this field is included, the client should use snapshot Merkle metadata to 128 | verify updates instead: 129 | 130 | ``` 131 | ("merkle_root": ROOT_HASH) 132 | ``` 133 | 134 | Where `ROOT_HASH` is the hash of the Merkle tree's root node. 135 | 136 | Note that snapshot Merkle metadata files do not need to be signed by a snapshot 137 | key because the path information will be verified based on the Merkle root 138 | provided in timestamp. Removing these signatures will provide additional space 139 | savings for clients. 140 | 141 | Previous versions of snapshot Merkle metadata files using the current timestamp 142 | key must remain available to clients and auditors. The repository may store 143 | snapshot Merkle metadata files using consistent snapshots to facilitate 144 | access to previous Merkle trees. 145 | 146 | ## Merkle tree verification 147 | 148 | If a client sees the `merkle_root` field in timestamp metadata, they will use 149 | the snapshot Merkle metadata to check version information. If this field is 150 | present, the client will download the snapshot Merkle metadata file only for 151 | the targets metadata the client is attempting to update. The client will verify the 152 | snapshot Merkle metadata file by reconstructing the Merkle tree and comparing 153 | the computed root hash to the hash provided in timestamp metadata. If the 154 | hashes do not match, the snapshot Merkle metadata is invalid. Otherwise, the 155 | client will use the version information in the verified snapshot Merkle 156 | metadata to proceed with the update. 157 | 158 | For additional rollback protection, the client may download previous versions 159 | of the snapshot Merkle metadata for the given targets metadata file. The client 160 | should perform this check immediately after verifying the current Merkle tree. After verifying 161 | these files, the client should compare the version information in the previous 162 | Merkle trees to the information in the current Merkle tree to ensure that the 163 | version numbers have never decreased. In order to allow for fast forward attack 164 | recovery (discussed further in Security Analysis), the client should only 165 | download previous versions whose root hashes were signed for with the same timestamp key. 166 | 167 | ## Auditing Merkle trees 168 | 169 | In order to ensure the validity of all targets metadata version information in the 170 | Merkle tree, third-party auditors should validate the entire tree each time it 171 | is updated. Auditors should download every snapshot Merkle file, verify the 172 | paths, check the root hash against the hash provided in timestamp metadata, 173 | and ensure that the version information has not decreased for each leaf. 174 | Alternatively, the repository may provide auditors with information about the 175 | contents and ordering of leaf nodes so that the auditors can more efficiently 176 | verify the entire tree. 177 | 178 | An auditor should validate all versions of the Merkle tree signed by the 179 | current timestamp key. For fast-forward attack recovery, the auditor should 180 | not check for a rollback attack after the timestamp key 181 | has been replaced. This means that all new auditors should check the Merkle 182 | trees signed with the current timestamp keys before attesting to the validity 183 | of the current Merkle tree. 184 | 185 | ## Client interaction with auditors 186 | 187 | Clients must ensure that snapshot Merkle trees have been verified by an auditor. 188 | To do so, implementations may use a few different mechanisms: 189 | 190 | * Auditors may provide an additional signature for timestamp metadata that 191 | indicates that they have verified the contents of the Merkle tree whose root 192 | is in that timestamp file. Using this signature, clients can check whether a 193 | particular third party has approved the Merkle tree. To use this mechanism, 194 | the auditor's key should be included in the root metadata. 195 | 196 | * Auditors may host a list of verified Merkle roots for a given repository, 197 | signed by the auditor's key. Clients may be configured with the auditor's key, 198 | or get it from the root metadata. 199 | 200 | * Clients may use a secure API to verify that a given Merkle root has been 201 | verified by an auditor. This API should provide compromise resilience similar to 202 | TUF's root metadata. 203 | 204 | ## Garbage collection 205 | 206 | When a threshold of timestamp keys are revoked and replaced, the repository no 207 | longer needs to store snapshot Merkle files signed by the previous timestamp 208 | keys. Replacing the timestamp keys is an opportunity for fast forward attack 209 | recovery, and so all version information from before the replacement is no 210 | longer valid. At this point, the repository may garbage collect all snapshot 211 | Merkle metadata files. 212 | 213 | # Security Analysis 214 | 215 | This proposal impacts the snapshot metadata, so this section will discuss the 216 | attacks that are mitigated by snapshot metadata in TUF. 217 | 218 | ## Rollback attack 219 | 220 | A rollback attack provides a client with an old, previously valid view of 221 | the repository. Using this attack, an attacker could convince a client to 222 | install a version from before a security patch was released. 223 | 224 | TUF currently protects against rollback attacks by checking the current time 225 | signed by timestamp and ensuring that no version information provided by 226 | snapshot has decreased since the last update. With both of these protections, 227 | a client that has a copy of trusted metadata is secure against a rollback 228 | attack to any version released 229 | before the previous update cycle, even if the timestamp and snapshot keys 230 | are compromised. 231 | 232 | Using snapshot Merkle trees, rollback attacks are prevented by both the 233 | client verification and by third party auditors. If no keys are compromised, 234 | the timestamp keys protect against a rollback attack by ensuring a valid 235 | snapshot Merkle tree. If the timestamp key is compromised, the client 236 | verification of previous Merkle trees provides rollback protection for the 237 | individual targets metadata files that are verified. However, if the attacker 238 | controls the repository and timestamp keys, they may provide malicious previous 239 | Merkle trees. For full rollback protection, clients rely on third party 240 | auditors. Third party auditors store the previous version of 241 | all metadata, and will detect when the version number decreases in a new 242 | Merkle tree. As long as the client checks for an auditor’s verification, the 243 | client will not install the rolled-back version of the target. 244 | 245 | In summary, without auditors, a client is vulnerable to rollback attacks when an attacker 246 | controls the timestamp key. With auditors, the client has the same rollback 247 | protection as the existing TUF specification. 248 | 249 | ## Fast forward attack 250 | 251 | If an attacker is able to compromise the timestamp key, they may arbitrarily 252 | increase the version number of a target in the snapshot Merkle metadata. If 253 | they increase it to a sufficiently large number (say the maximum integer value), 254 | the client will not accept any future version of the target as the version 255 | number will be below the previous version. 256 | 257 | In the current specification, repositories can recover from a fast forward 258 | attack by replacing a threshold of timestamp keys. If the client sees that 259 | a threshold of timestamp keys were replaced, it deletes the currently trusted 260 | version information. 261 | 262 | Snapshot Merkle trees also reset snapshot information after a replacement of 263 | a threshold of timestamp keys in order to recover from fast forward attacks. 264 | Auditors and clients should not check version information from before a 265 | timestamp key replacement when verifying the Merkle tree. 266 | 267 | Thus, fast forward attack recovery with snapshot Merkle trees is the same 268 | as in the existing specification, but must be performed by both clients and 269 | auditors. 270 | 271 | ## Mix and match attack 272 | 273 | In a mix and match attack, an attacker combines images from the current 274 | snapshot with images from other snapshots, potentially introducing 275 | vulnerabilities. 276 | 277 | Currently, TUF protects against mix and match attacks by providing a snapshot 278 | metadata file that contains all targets metadata files available on the 279 | repository. Therefore, a mix and match attack is only possible in an 280 | attacker is able to compromise the timestamp and snapshot keys to create 281 | a malicious snapshot metadata file. 282 | 283 | A snapshot Merkle tree prevents mix and match attacks by ensuring that all 284 | targets files installed come from the same snapshot Merkle tree. If all targets 285 | have version information in the same snapshot Merkle tree, the properties of 286 | secure hash functions ensure that these versions were part of the same snapshot. 287 | As in the existing specification, a mix and match attack would be possible 288 | if an attacker was able to replace the snapshot Merkle tree using compromised 289 | timestamp keys. 290 | 291 | Snapshot Merkle trees provide the same protection against mix and match attacks 292 | as the existing specification. 293 | 294 | 295 | # Backwards Compatibility 296 | 297 | This TAP is not backwards compatible. The following table describes 298 | compatibility for clients and repositories. 299 | 300 | | Parties that support snapshot Merkle trees | Result | 301 | | ------------------------------------------ | ------ | 302 | | Client and repository support this TAP | Client and repository are compatible | 303 | | Client supports this TAP, but repository does not | Client and repository are compatible. The timestamp metadata provided by the repository will never contain the `merkle_root` field, and so the client will not look for snapshot Merkle metadata. | 304 | | Repository supports this TAP, but client does not | Client and repository are not compatible. If the repository uses snapshot Merkle metadata, the client will not recognise the `merkle_root` field as valid. | 305 | | Neither client nor repository supports this TAP | Client and repository are compatible | 306 | 307 | # Augmented Reference Implementation 308 | 309 | https://github.com/theupdateframework/python-tuf/pull/1113/ 310 | TODO: auditor implementation 311 | 312 | # Copyright 313 | 314 | This document has been placed in the public domain. 315 | -------------------------------------------------------------------------------- /tap17.md: -------------------------------------------------------------------------------- 1 | * TAP: 17 2 | * Title: Remove Signature Wrapper from the TUF Specification 3 | * Version: 1 4 | * Last-Modified: 11/11/2021 5 | * Author: Aditya Sirish A Yelgundhalli, Marina Moore 6 | * Type: Standardization 7 | * Status: Draft 8 | * Content-Type: markdown 9 | * Created: 30/04/2021 10 | * Requires: TAP-11, TAP-14 11 | * +TUF-Version: 12 | * +Post-History: 13 | 14 | # Abstract 15 | 16 | This TUF Augmentation Proposal (TAP) proposes removing the definition of a 17 | specific signature wrapper and key definitions, and instead defines certain 18 | properties a wrapper must have. Further, it suggests POUF-1 as an example 19 | implementors can refer to when choosing to generate TUF metadata. 20 | 21 | # Specification 22 | 23 | The TUF specification as of v1.0.25 uses a custom signature wrapper. At the 24 | time of authoring this document, the primary reference implementation written 25 | in Python also generates TUF metadata using the same signature wrapper. 26 | 27 | However, TUF does not mandate the use of this signature wrapper, nor any 28 | specific metaformat. Indeed, 29 | [TAP-11, "Using POUFs for Interoperability"](https://github.com/theupdateframework/taps/blob/master/tap11.md) 30 | enables adopters to make their own decisions for their implementations, and 31 | provides a mechanism for them to document their decisions. 32 | [POUF-1](/POUFS/reference-POUF/pouf1.md) is the POUF for the official reference 33 | implementation, and it seems like the obvious choice for this information to be 34 | specified. 35 | 36 | Section 4.2 of the TUF specification, titled "File formats: general principles" 37 | may be replaced by a description of the properties that any signature wrapper used 38 | by a TUF implementation must provide. Some important properties: 39 | 40 | * SHOULD include an authenticated payload type 41 | * SHOULD avoid depending on canonicalization for security 42 | * SHOULD NOT require the verifier to parse the payload before verifying 43 | * SHOULD NOT require the inclusion of signing key algorithms in the signature 44 | * MUST support the inclusion of multiple signatures in a file 45 | * SHOULD support a hint indicating what signing key was used, i.e., a KEYID 46 | 47 | The presence of an authenticated payload type can be valuable for a project like TUF, 48 | with multiple implementations and derivatives. Indeed, every POUF that describes an 49 | implementation MUST choose a unique payload type, ensuring that there is no confusion 50 | about which implementation generated some piece of metadata. 51 | 52 | # Motivation 53 | 54 | TAP-11 introduced the concept of POUFs but the TUF specification continues to 55 | specify example formats, namely those used by the reference implementation as 56 | of June 2021. These definitions are essentially replicated in POUF-1, which is 57 | meant to be the authoritative source for information about the reference 58 | implementation. By replacing these definitions with *properties* that a wrapper 59 | must possess, the specification can aid adopters with the development of their 60 | implementations and the POUF can serve as an example. In this scenario, both 61 | documents are serving the purpose originally envisioned for them. 62 | 63 | Further, the examples used in the specification are from the old signature 64 | wrapper that includes certain side effects: 65 | * it requires canonicalization before signature verification 66 | * it does not allow for distinguishing different implementations that may have 67 | slightly different formats, i.e., it's missing a payload type 68 | 69 | # Rationale 70 | 71 | Moving the signature wrapper details out of the specification, and instead 72 | requiring adopters to refer to POUFs for specifics of an implementation ensures 73 | a clean separation between implementation details and the TUF specification. 74 | Indeed, it also ensures that the focus of the reader is on only the TUF 75 | primitives rather than burdening them with the specifics of the signature 76 | wrapper. 77 | 78 | # Security Analysis 79 | 80 | Any implementations that build on the properties listed in this document 81 | will have their security enhanced. 82 | 83 | # Backwards Compatibility 84 | 85 | The changes proposed in this TAP are backwards compatible with respect to the 86 | TUF specification. However, for implementations looking to switch to a 87 | signature wrapper with the properties described here, the change may be 88 | backwards incompatible. In these instances, the implementations SHOULD set a 89 | transition period during which they support both old-style and new-style 90 | envelopes. This transition period MUST be clearly communicated to their users 91 | using their standard channels. 92 | [TAP-14, "Managing TUF Versions"](https://github.com/theupdateframework/taps/blob/master/tap14.md) 93 | contains some useful information about distributing metadata in multiple formats 94 | that can be used during the transition period. 95 | 96 | # Augmented Reference Implementation 97 | 98 | TODO: POUF-1 will be updated separately, along with the implementation itself. 99 | See POUF-1 for details about the reference implementation. 100 | 101 | # Copyright 102 | 103 | This document has been placed in the public domain. 104 | 105 | # References 106 | 107 | * [TAP-11](https://github.com/theupdateframework/taps/blob/master/tap11.md) 108 | * [TAP-14](https://github.com/theupdateframework/taps/blob/master/tap14.md) 109 | * [File formats in TUF Specification](https://theupdateframework.github.io/specification/latest/index.html#file-formats-general-principles) 110 | * [POUF-1](/POUFS/reference-POUF/pouf1.md) 111 | -------------------------------------------------------------------------------- /tap18.md: -------------------------------------------------------------------------------- 1 | * TAP: 18 2 | * Title: Ephemeral identity verification using sigstore's Fulcio for TUF developer key management 3 | * Version: 0 4 | * Last-Modified: 06/04/2023 5 | * Author: Marina Moore, Joshua Lock, Asra Ali, Luke Hinds, Jussi Kukkonen, Trishank Kuppusamy, axel simon 6 | * Type: Standardization 7 | * Status: Draft 8 | * Content-Type: markdown 9 | * Created: 27/07/2021 10 | * TUF-Version: 11 | 12 | # Abstract 13 | In order to achieve end-to-end software update security, TUF requires developers to sign metadata about updates with a private key. However, this has proven challenging for some implementers as developers then have to create, store, and secure these private keys in order to ensure they remain private. This TAP proposes adding a new signing option using sigstore's Fulcio project to simplify developer key management by allowing developers to use existing accounts to verify their identity. TUF "targets" roles may delegate to Fulcio identities instead of private keys, and these identities (and the corresponding certificates) may be used for verification. 14 | 15 | # Motivation 16 | Developer key management has been a major concern for TUF adoptions, especially for projects with a small number of developers or limited resources. TUF currently requires that every targets metadata signer creates and manages a private key, including secure storage of the key over a long period of time to prevent it leaking to an attacker. However, many developers that upload packages to large TUF adoptions, including the Python Package Index (PyPI), manage small or under-resourced projects and do not want the extra burden of having to protect a private key for use in deployment. 17 | 18 | Protecting a private key from loss or compromise is no simple matter. [Several](https://blog.npmjs.org/post/185397814280/plot-to-steal-cryptocurrency-foiled-by-the-npm) [attacks](https://jsoverson.medium.com/how-two-malicious-npm-packages-targeted-sabotaged-one-other-fed7199099c8) on software update systems have been achieved through the use of a compromised key, as securing private keys can be challenging and sometimes expensive (using hardware tokens such as HSMs etc), especially over a period of time. 19 | 20 | This TAP proposes a way for signers to use their existing OpenID Connect (OIDC) accounts – such as an email account – as an identity instead of using a key. This means that they do not have to manage any additional keys or passwords. 21 | 22 | # Rationale 23 | In a previous draft of [PEP 480](https://www.python.org/dev/peps/pep-0480/), the authors proposed using [MiniLock](https://web.archive.org/web/20221207042405/http://www.minilock.io/) – a tool which derives ed25519 keys from a user-chosen passphrase – to simplify developer key management. However, this requires developers to remember a new and additional passphrase for use when uploading packages. Furthermore, the MiniLock project is [no longer maintained](https://web.archive.org/web/20191106011621/http://github.com/kaepora/miniLock) and has been archived. 24 | 25 | In this TAP, we instead propose use of the sigstore project. Sigstore has a growing number of adoptions, and provides a simple mechanism for signers to verify their identity using short-lived keys and ad-hoc certificates issued on the basis of OIDC. Sigstore provides a few services, including [Fulcio](https://github.com/sigstore/fulcio) (a CA) and [Rekor](https://github.com/sigstore/rekor) (a transparency log). With sigstore, long-term efforts to keep private keys secure are not necessary, as signing keys are ephemeral and only used for a single signing event. Fulcio certificates and client generated signatures are published to a timestamped transparency log managed by Rekor so that verifiers can ensure that the certificates were valid at the time of the signature. 26 | 27 | # Specification 28 | In addition to supporting existing TUF targets delegations, this TAP adds support for delegations to any OIDC identity, including signer email addresses, to be verified by Fulcio. These delegations MAY replace public keys for signers (such as ed25519 keys) in order to simplify their key management. Fulcio generates short-lived signing keys and uses certificates to bind these keys to an identity backed by OIDC authentication. Because the ephemeral keys listed in the certificates are short-lived, the signer will not be responsible for protecting signing keys in the long term and in practice SHOULD discard them immediately after signing. Fulcio certificates are automatically uploaded to the timestamped Rekor transparency log, so repositories and clients can verify that the certificate was valid at the time of signing. 29 | 30 | ## Delegation format 31 | In order to facilitate use of Fulcio, delegations may list an OIDC identity, such as an email address, and location of a Fulcio server instead of a public key. To do so, this TAP adds a "sigstore-oidc" keytype for a KEY with the following format: 32 | 33 | ``` 34 | { 35 | "keytype": "sigstore-oidc", 36 | "scheme": "Fulcio", 37 | "keyval": { 38 | "identity": IDENTITY, 39 | "issuer": ISSUER 40 | } 41 | } 42 | ``` 43 | 44 | Where IDENTITY is the OIDC identity of the party who is authorized to sign and ISSUER is the OIDC entity used by Fulcio for verification. For example, identity could be "hello@gmail.com" with an issuer "https://accounts.google.com". Both IDENTITY and ISSUER are required for this keytype. 45 | 46 | The root certificate or certificate chain for the Fulcio server MUST be obtained using the Sigstore [root of trust](https://github.com/sigstore/root-signing). The client MUST use a single Fulcio instance. 47 | 48 | 49 | ## Signature format 50 | A signature using a Fulcio key MUST include the Fulcio certificate for use in verification. For this verification, this TAP adds an additional 'bundle' field to 'signatures'. With this field, signatures would look like: 51 | 52 | ``` 53 | { 54 | "keyid" : KEYID, 55 | "sig": SIGNATURE, 56 | "bundle": BUNDLE 57 | } 58 | ``` 59 | Where BUNDLE is an object that contains the verification information (transparency log references or timestamps), Fulcio X.509 signing certificate, and a signature over targets metadata, conforming to the [format defined by Sigstore](https://github.com/sigstore/protobuf-specs/blob/main/protos/sigstore_bundle.proto). The transparency log verification information includes a signed timestamp (SET) from Rekor promising inclusion in the Rekor transparency log. 60 | SIGNATURE is the 'message_signature' from the bundle in hex-encoded form. 61 | 62 | ## Signing 63 | In order to sign metadata using Fulcio, a signer MUST: 64 | 65 | * Initiate an OIDC session to obtain an identity token signed by the OIDC identity provider's public key containing the signer's IDENTITY. 66 | * Generate a key pair locally. 67 | * Create a certificate signing request containing the subject of the identity token. Sign this certificate with the generated private key. 68 | * Request a short-lived certificate from Fulcio by sending the certificate signing request along with the identity token. 69 | * Fulcio will upload the certificate to a Certificate Transparency log. 70 | * Use the generated private key to create signature over targets metadata. 71 | * Upload the certificate, signature, and hash of the targets metadata to the timestamped Rekor transparency log. Rekor will return an SET with a timestamp that indicates that Rekor received the request and will include it in the log. 72 | * Create a bundle that contains the signature, Fulcio certificate, SET. 73 | 74 | Most of these steps SHOULD be done automatically using a tool (such as Sigstore), to simplify operations for signers and minimise the risk of human errors. 75 | 76 | 77 | ## Verification 78 | This signature, and the associated Rekor timestamp obtained by querying the Rekor server, MUST be verified by a centralized authority and MAY be verified by the end user. This centralized authority MAY be a repository, or MAY be a separate service. The verifier MUST obtain the Rekor root keys and the certificate log public key using a secure out of band method prior to verifying the signature and associated certificate. 79 | 80 | While performing the steps in the [TUF client workflow](https://theupdateframework.github.io/specification/latest/#detailed-client-workflow), if the client encounters a signature that uses a Fulcio certificate, the client MUST perform offline verification. In addition, a centralized entity (such as the repository) MUST perform offline verification. 81 | 82 | Offline verification includes the following steps: 83 | 84 | * Verify the signature on the certificate to ensure that the signature chains up to the trusted Fulcio root and that the identity and issuer in the certificate match those found in the delegation. 85 | * Verify the Fulcio certificate's bundled CT inclusion proof with the trusted certificate log public key. 86 | * Verify the signature on the TUF metadata using the key from the Fulcio certificate. 87 | * Verify the SET to ensure that the signature was signed during certificate validity. 88 | 89 | Similar to signing, this verification SHOULD be done with existing Sigstore tooling. 90 | Periodically the centralized authority SHOULD perform online verification (described below) of all Rekor uses. 91 | Online clients MAY additionally perform online verification. Offline clients rely on the centralized authority for all online checks. Online verification is described in the auditors section below. 92 | 93 | ## Auditors and Monitoring 94 | 95 | Online verification requires the following steps: 96 | 97 | 1. Obtain the most recent Rekor signed tree head. 98 | * Query the Rekor transparency log for a consistency proof against your current signed tree head. 99 | * Verify this consistency proof. 100 | * Persist the newest signed tree head. 101 | 1. Query the Rekor transparency log for a proof of inclusion against the certificate and TUF metadata. 102 | 1. Verify this inclusion proof. 103 | 1. Verify that the root hash of the inclusion proof is consistent with the signed tree head verified in step 1. 104 | 105 | Online verification SHOULD be performed periodically by a centralized entity with the ability to remove compromised metadata from the repository and MAY be performed by clients. 106 | 107 | Signers SHOULD monitor the transparency log (TL) and look for certificates associated with their OIDC accounts to look for unauthorized activity. If they see a certificate on the TL that they did not issue, the signer SHOULD replace any compromised metadata (creating new Fulcio certificate), and ensure the security of their OIDC account. If the OIDC account cannot be recovered, the signer MUST contact the role that delegates to them to replace the delegation to their OIDC identity. 108 | 109 | In addition to signer monitoring, the TL SHOULD have auditors that watch the log by performing online verification for all uses in TUF metadata for any suspicious activity. If something bad (such as a mutation in the log, a deviation from the append-only policy, or invalid inclusion proofs) is found in the TL, then auditors MUST indicate this to clients to ensure they don't use bad certificates. Clients SHOULD have a way to ensure that the transparency log has been audited. For example, auditors may upload signed targets metadata to the repository upon valid completion of an audit. Clients can look for the auditor signature on targets metadata using [multi-role delegations](https://github.com/theupdateframework/taps/blob/master/tap3.md) before verifying any Fulcio-signed delegated targets. The auditor MUST only sign metadata if all signatures in the TL look good. If the auditor detects a problem, they SHOULD revoke the auditor-signed metadata. The repository SHOULD be an auditor of the log. 110 | 111 | If the bad certificates are due to a compromised Fulcio server, Fulcio MUST revoke its certificate and distribute a new certificate in the TUF Sigstore root, and inform any affected clients of the compromise. 112 | 113 | # Security Analysis 114 | 115 | Our [threat modeling](https://docs.google.com/document/d/1fkz8zO35zAIXlvTNSQYyLSK_T6n0G8STGxCoxB3RNQo/edit#) has found that using Fulcio with TUF namespacing is mostly security neutral with the existing TUF specification as long as different accounts are used for login and for the OIDC-backed signatures. This TAP improves security by eliminating the risk of signers losing their keys if they chose to use Fulcio instead of a traditional public key cryptosystem. However, it adds additional services that may be compromised: the signer's OIDC credentials, the Fulcio server, the Rekor transparency log, and the identity provider. In this section, we will analyze the impact and recovery in each of these cases. 116 | 117 | If a signer's OIDC credentials are compromised, the signer SHOULD use existing TUF processes for revocation. Specifically they SHOULD ask the delegator to replace any metadata that includes the compromised OIDC account. If the signer's credentials were compromised, but later recovered through the OIDC provider, the signer may still use these credentials, but any metadata files that were created while the credentials were compromised should be replaced with a higher version of those metadata files so that the compromised files will not be downloaded (using the existing snapshot protection). 118 | 119 | If the Fulcio server is compromised, it may issue certificates on behalf of any attacker who uses Fulcio to verify their identity. However, the Fulcio server is backed by keys that are signed by the offline TUF Sigstore root keys, and so it is possible to recover from any Fulcio server compromise using TUF's revocation process. Additionally, all Fulcio certificates are published to two transparency logs (Rekor and the Fulcio Certificate Transparency log), so auditors of either log will notice if the Fulcio server is misbehaving and indicate this to users, for example through the use of [multi-role delegations](https://github.com/theupdateframework/taps/blob/master/tap3.md) to a threshold of both auditor-signed metadata and developer-signed metadata. 120 | 121 | If only one of the transparency logs is compromised, the attacker will not be able to do anything without cooperation from the Fulcio server because the attack will not be able to create a valid certificate without a compromised Fulcio instance. However, if the attacker compromises both the Fulcio server and the transparency log, they would be able to issue fake Fulcio certificates that also appear valid on the transparency log. If this happens, signers auditing the transparency log would notice the mis-issued certificates, and the Fulcio server and transparency log could both securely replace their key material using offline root key from the TUF Sigstore root. Implementations using this TAP SHOULD ensure that there are active auditors watching both the transparency logs. 122 | 123 | If the identity provider used for OIDC is compromised, they may issue tokens with attacker controlled identities. Metadata signed by certificates from compromised identity providers can be revoked using the usual TUF process, and the identity providers can be removed from the delegating TUF metadata. 124 | 125 | By default, clients will perform offline verification. They may choose to additionally perform online verification. In practice, existing uses of transparency logs use offline verification as it saves bandwidth and maximum merge delays on the transparency log mean that online verification is not immediately available. This is because the transparency log will batch additions to the log. Offline verification relies on a signature from the Rekor key that the entry will be included and that the entry was seen at a certain time. This is the same key that signs the Rekor signed tree head in online verification. If the Rekor key is compromised, both of these verification types could be tricked. However, monitors are able to detect bad behavior once entries are added to the log, and monitor signatures can be used to provide additional assurance. 126 | 127 | 128 | # Backwards Compatibility 129 | 130 | Clients that do not recognize Fulcio certs will not be able to validate signatures from Fulcio certs, but they will be able to parse the metadata. 131 | 132 | # Augmented Reference Implementation 133 | 134 | The pull request [#181](https://github.com/theupdateframework/go-tuf/pull/181) in go-tuf adds this feature. 135 | 136 | # Copyright 137 | This document has been placed in the public domain. 138 | -------------------------------------------------------------------------------- /tap2.md: -------------------------------------------------------------------------------- 1 | * TAP: 2 | * Title: 3 | * Version: 4 | * Last-Modified: 5 | * Author: 6 | * Type: 7 | * Status: 8 | * +Content-Type: 9 | * +Requires: 10 | * Created: 11 | * +TUF-Version: 12 | * +Post-History: 13 | * +Replaces: 14 | * +Superseded-By: 15 | 16 | # Abstract 17 | 18 | A short (~200 word) description of the technical issue being addressed. 19 | 20 | # Motivation 21 | 22 | The motivation is critical for TAPs that want to change TUF. It should clearly explain why the existing framework specification is inadequate to address the problem that the TAP solves. TAP submissions without sufficient motivation may be rejected outright. 23 | 24 | # Rationale 25 | 26 | The rationale fleshes out the specification by describing what motivated the design and why particular design decisions were made. It should describe alternate designs that were considered and related work, e.g. how the feature is supported in other frameworks. The rationale should provide evidence of consensus within the community and discuss important objections or concerns raised during discussion. 27 | 28 | # Specification 29 | 30 | The technical specification should describe the syntax and semantics of any new feature. The specification should be detailed enough to allow competing, interoperable implementations for at least the current major TUF platforms (TUF, Notary, go-tuf). 31 | 32 | # Security Analysis 33 | 34 | The TAP should show, in as simple as possible a manner, why the proposal would not detract from existing security guarantees. (In other words, the proposal should either maintain or add to existing security.) This need not entail a mathematical proof. For example, it may suffice to provide a case-by-case analysis of key compromise over all foreseeable roles. To take another example, if a change is made to delegation, it must preserve existing delegation semantics (unless the TAP makes a good argument for breaking the semantics). 35 | 36 | # Backwards Compatibility 37 | 38 | All TAPs that introduce backwards incompatibilities must include a section describing these incompatibilities and their severity. The TAP must explain how the author proposes to deal with these incompatibilities. TAP submissions without a sufficient backwards compatibility treatise may be rejected outright. 39 | 40 | # Augmented Reference Implementation 41 | 42 | The augmented reference implementation must be completed before any TAP is given status "Final", but it need not be completed before the TAP is accepted. While there is merit to the approach of reaching consensus on the specification and rationale before writing code, the principle of "rough consensus and running code" is still useful when it comes to resolving many discussions of API details. The final implementation must include test code and documentation appropriate for the TUF reference. 43 | 44 | # Copyright 45 | 46 | Each TAP must either be explicitly labeled as placed in the public domain (see TAP 1 as an example) or licensed under the [Creative Commons Attribution 4.0 International License](https://creativecommons.org/licenses/by/4.0/). 47 | -------------------------------------------------------------------------------- /tap20.md: -------------------------------------------------------------------------------- 1 | * TAP: 20 2 | * Title: Self-revocation 3 | * Version: 1 4 | * Last-Modified: 29-Jan-2024 5 | * Author: Marina Moore 6 | * Status: Accepted 7 | * Content-Type: text/markdown 8 | * Created: 19-Jan-2024 9 | 10 | 11 | # Abstract 12 | This TAP proposes a mechanism for independent key revocation that allows any key 13 | holder to revoke their key without waiting on delegator. Performing a revocation 14 | in TUF requires parties that delegated trust to a role to change their delegation 15 | to remove the revoked key. However, this introduces a lag between when a key 16 | holder becomes aware of a compromise and when the delegator responds to this 17 | compromise. This TAP will reduce lag time between a key compromise and a 18 | revocation by allowing any key holder to revoke the role they are trusted to sign. 19 | 20 | The revocation mechanism is designed to be used by all targets roles. Targets 21 | roles, especially delegated targets roles, are not controlled by the repository, 22 | and so have the greatest likelihood of a delay before revocation. 23 | 24 | This TAP uses the rotation mechanism from TAP 8 to achieve revocation. It 25 | adds a 'null key' that, when rotated to, revokes a role. If a rotation to a null 26 | key is detected, it causes the role to no longer be trusted. The client will 27 | detect a rotation to a null key and treat it as if the metadata was unsigned. 28 | A role could use a revocation if they suspect a threshold of keys have been 29 | compromised (a lost hard drive, system breach, etc). A rotation to a null key 30 | revokes trust in the role, not specific keys, so all keys associated with the 31 | role will be invalid after a rotation to null. If only a single key needs to be 32 | replaced, it can be safely rotated using the mechanism in TAP 8 especially in 33 | the case that a threshold of keys is required. 34 | 35 | A delegator to a role A is able to help A recover from a rotation to null of A 36 | by delegating to a new set of keys for A. This ensures that the delegator is 37 | still the source of trust, but allows the role to act independently. 38 | 39 | 40 | # Motivation 41 | 42 | The following use case can benefit from an independent revocation mechanism: 43 | 44 | 45 | ## Community repositories 46 | 47 | Community repositories are often managed by a small group of volunteer 48 | administrators. These administrators are responsible for managing the targets 49 | metadata that delegates to all projects on the repository, often with an offline 50 | key for additional security. This means that any revocations of compromised keys 51 | will not be reflected in the metadata until the volunteer administrator learns 52 | about and verifies the revocation, then manually signs new metadata with their 53 | offline key that either removes the revoked key(s), or replaces them. Each of 54 | these steps can be time consuming, and the whole process may take many hours or 55 | even days. During this period, users will continue to use the compromised key. 56 | 57 | # Rationale 58 | 59 | TUF is a framework for securing software update systems that is designed 60 | to maintain trust in the system through key compromises. The trust 61 | is rooted in a quorum of root keys, which delegate trust to other roles. 62 | When the root keys delegate trust to a role T for all names, this can be 63 | used to delegate some names to role D, etc. If one of role D's keys is 64 | compromised, they have to wait for role T to replace the key with a new, 65 | trusted key. 66 | 67 | With this proposal, the owner of role D can 68 | revoke their role without relying on the delegator. This will improve 69 | response time to key compromises. 70 | 71 | TAP 8 already proposes a mechanism for key rotation. We utilize document formats 72 | from that proposal to support key revocation. 73 | 74 | 75 | # Specification 76 | 77 | ## Rotate file (from TAP 8) 78 | 79 | The signed portion of a `rotate` file is as follows (there's also a 80 | signatures wrapper as in the TUF specification, not shown here): 81 | 82 | ```python 83 | { 84 | "_type" : "rotate", 85 | "version" : VERSION, 86 | "role" : ROLE, 87 | "keys" : { 88 | KEYID : KEY 89 | , ... } , 90 | "threshold" : THRESHOLD 91 | } 92 | ``` 93 | 94 | Where ROLE, KEYID, KEY, and THRESHOLD are as defined in the original 95 | TUF specification. The value of ROLE has to be the same as the role for the 96 | delegation. The value of THRESHOLD is its new value. VERSION is the index of 97 | this rotate file, incrementing by 1 on each rotation. The keys specify the new 98 | valid keys 99 | and associated key ids (which may be a subset or superset of 100 | the old ones). A rotate file does _not_ contain an expiration date, 101 | it is meant to be signed once and never modified. The rotate 102 | file has to be signed with an old threshold of old keys. 103 | 104 | This rotate file will be named `ROLE.rotate.VERSION` where ROLE and VERSION are 105 | defined as above and go into a 'rotate' folder on the repository that 106 | contains all rotate files for the repository. 107 | 108 | 109 | ## Rotation to Null 110 | 111 | Clients need to check for rotations to a null key, and any delegation pointing 112 | to a rotation to a null key is invalid. The null key is a hard coded value used 113 | across TUF implementations. This enables a role to explicitly revoke their 114 | own key(s) by introducing a rotation to null. As example rotate file would be: 115 | 116 | ```python 117 | { 118 | "_type" : "rotate", 119 | "version" : 2, 120 | "role" : "foo", 121 | "keys" : { 122 | NULL 123 | }, 124 | "threshold" : 1 125 | } 126 | ``` 127 | 128 | where NULL is the null key. 129 | 130 | ### Prioritizing Self Revocation 131 | 132 | Rotation files are immutable unless replaced with a revocation. 133 | This is the only case in which they can be replaced or 134 | modified. If a key holder wants to rotate to a different 135 | key, without having access to their currently delegated private key, 136 | this requires a key revocation by the delegating metadata. 137 | 138 | ## Client workflow 139 | 140 | Rotate files will be downloaded by clients as described in TAP 8. Once a 141 | rotate file is downloaded and verified, the client will check for a rotation 142 | to null. If such a rotation to null is found, the client will treat the given 143 | role as revoked. 144 | 145 | # Security Analysis 146 | 147 | There should be no negative security impact. The major benefits are 148 | that many security-sensitive revocations that require key use by 149 | multiple parties, will now be much easier to do. 150 | 151 | Clients need to take care to check for revocation (rotate 152 | files that contain a null key). This shall be handled in the 153 | same manner as an invalid metadata signature on by the role possessing 154 | the key. The role will be invalid until it is re-delegated to with a new 155 | rolename and key. 156 | Clients MUST use snapshot metadata to ensure that they receive all rotate files 157 | in the chain. 158 | 159 | Intentionally rotating to null enables a repository, a 160 | project, and individuals to explicitly revoke their key material 161 | themselves. An individual whose key is compromised can introduce 162 | a rotation to null, and all delegations to them will be invalid. 163 | 164 | As a general note, this TAP only extends the possibilities of a target, 165 | but the delegation mechanism is still in place - i.e. a key higher up 166 | in the delegation can always revoke / modify the delegation itself. 167 | 168 | 169 | # Backwards compatibility 170 | 171 | This TAP is not backwards compatible since clients have to download and 172 | verify the revocations. 173 | 174 | # Augmented Reference Implementation 175 | 176 | https://github.com/theupdateframework/python-tuf/pull/2257/files 177 | 178 | # Copyright 179 | 180 | This document has been placed in the public domain. 181 | -------------------------------------------------------------------------------- /tap3.md: -------------------------------------------------------------------------------- 1 | * TAP: 3 2 | * Title: Multi-role delegations 3 | * Version: 1 4 | * Last-Modified: 12-Feb-2019 5 | * Author: Trishank Karthik Kuppusamy, Sebastien Awwad, Evan Cordell, 6 | Vladimir Diaz, Jake Moshenko, Justin Cappos 7 | * Status: Accepted 8 | * Content-Type: text/markdown 9 | * Created: 16-Sep-2016 10 | * TUF-Version: 1.0.0 11 | 12 | # Abstract 13 | 14 | This TAP allows a target to be delegated to a combination of roles on a 15 | repository, all of whom must sign the same hashes and length of the target. 16 | This is done by adding the [AND 17 | relation](https://en.wikipedia.org/wiki/Logical_conjunction) to delegations. 18 | 19 | # Motivation 20 | 21 | TAP 3 has been motivated by the following use case. 22 | 23 | ## Use case 1: requiring a combination of roles to sign the same targets 24 | 25 | In some cases, it is desirable to delegate targets to a combination of roles in 26 | order to increase compromise-resilience. For example, a project may require 27 | both its release engineering and quality assurance roles to sign for targets on 28 | the repository. Both roles are then required to sign the same hashes and 29 | length of the targets. This is done so that, assuming that both roles use 30 | different sets of keys, the compromise of either one of these roles is 31 | insufficient to execute arbitrary software attacks. 32 | 33 | # Rationale 34 | 35 | We introduce this TAP because there is no mechanism in place to support use 36 | case 1. TUF uses [prioritized and terminating 37 | delegations](https://theupdateframework.io/papers/protect-community-repositories-nsdi2016.pdf) to 38 | search for metadata about a desired target in a controlled manner. 39 | 40 | Using multiple delegations, one can delegate the same target to multiple roles, 41 | so that a role with low priority can provide metadata about the target even if 42 | a role with high priority does not. Any one of these roles is permitted to 43 | provide different metadata (i.e., length and hashes) about the target. 44 | Effectively, this allows TUF to support [OR 45 | relation](https://en.wikipedia.org/wiki/Logical_disjunction) in delegations. 46 | 47 | The problem is that TUF presently does not have a mechanism to support the AND 48 | relation in delegations, as it is currently not possible to require that a 49 | combination of delegations sign for the same hashes and length of a 50 | target. Also, there is no way to require that a minimum number of 51 | delegations sign for the same hashes and lengths. The latter is needed in 52 | cases where it is not known which combination of delegations will eventually 53 | sign for targets. 54 | 55 | Although the reader might observe that the key threshold feature allows an AND 56 | relation within one role that can in some simple cases lead to the same 57 | functionality (a requirement of all of a set of keys signing off), this option 58 | is less versatile. For one, the keys must sign the same piece of metadata and 59 | those signatures must sit in the same file. Secondly, existing functionality 60 | doesn't enable multiple roles with flexible thresholds and key sets to be 61 | required to sign off together, at least not without leading to an explosion in 62 | the number of delegations and roles required. 63 | 64 | 65 | # Specification 66 | 67 | In order to support use case 1, we propose the following adjustments to the 68 | file format of targets metadata. 69 | 70 | ## The previous file format of targets metadata 71 | 72 | In the [previous 73 | version](https://github.com/theupdateframework/python-tuf/blob/70fc8dce367cf09563915afa40cffee524f5b12b/docs/tuf-spec.txt#L766-L776) 74 | of the specification, each delegation could specify only a _single_ role as 75 | required to sign the given set of targets. 76 | 77 |
 78 | {
 79 |   "signed": {
 80 |     "delegations": {
 81 |       "roles": [
 82 |         // This is the first delegation to a single role.
 83 |         {
 84 |           // We specify the name, keyids, and threshold of a single role as
 85 |           // required to sign the following targets.
 86 |           "name": ROLENAME-1,
 87 |           "keyids": [KEYID-1],
 88 |           "threshold": THRESHOLD-1,
 89 |           "paths": ["/foo/*.pkg"],
 90 |           "terminating": false,
 91 |         },
 92 |         // This is the second delegation to a single role.
 93 |         // Note that this delegation is separate from the first one.
 94 |         // The first delegation may override this delegation.
 95 |         {
 96 |           "name": ROLENAME-2,
 97 |           "keyids": [KEYID-2],
 98 |           "threshold": THRESHOLD-2,
 99 |           "paths": ["/foo/bar.pkg"],
100 |           "terminating": false,
101 |         }
102 |         // Note that, unfortunately, there is no way to require multiple
103 |         // roles to sign targets in a single delegation.
104 |       ],
105 |       ...
106 |     },
107 |     ...
108 | }
109 | 
110 | 111 | ## The new file format of targets metadata 112 | 113 | Using the new file format of targets metadata, a delegation may specify 114 | _multiple_ role names as required to sign, instead of a single one. 115 | 116 |
117 | {
118 |   "signed": {
119 |     "keys_for_delegations": {KEYID: {"keytype: KEYTYPE, "keyval": KEYVAL}, ...},
120 |     "delegations": [
121 |         {
122 |           "name": DELEGATION-NAME,
123 |           "paths": [PATHPATTERN-1, PATHPATTERN-2, ...],
124 |           "terminating": BOOLEAN,
125 |           "min_roles_in_agreement": NUM_ROLES,
126 |           "roleinfo": [
127 |             {
128 |               "rolename": ROLENAME,
129 |               "keyids": [KEYID],
130 |               "threshold": THRESHOLD,
131 |             }
132 |           ]
133 |         },
134 |         // Multiple delegations can be specified here after the first one.
135 |         ...
136 |     ]
137 |   },
138 | }
139 | 
140 | 141 | As we argue in the [security analysis](#security-analysis), this allows us to 142 | support the AND relation in delegations without breaking existing security 143 | guarantees. 144 | 145 | ### Example: requiring a combination of roles to sign the same targets 146 | 147 | The following targets metadata file illustrates how a project may require a 148 | single role to sign some targets, but multiple roles to sign other targets: 149 | 150 |
151 | {
152 |   "signed": {
153 |     // These are the full public keys for each KEYID listed in "delegations."
154 |     "keys_for_delegations": {'ca9781...': {"keytype: "ed25519", "keyval": KEYVAL},
155 |         'acac86...': {...},
156 |         'de7d1b...': {...},
157 |         '1a2b41...': {...},
158 |         '93ec2c...': {...},
159 |         'f2d502...': {...},
160 |         'fce9cf...': {...},
161 |         '498aeb...': {...}},
162 | 
163 |     // "delegations" associates KEYIDs (of the keys above) with roles.
164 |     "delegations": [
165 |         // This is the first delegation.
166 |         {
167 |           "name": "first_delegation",
168 |           // These targets must be signed by this single role.
169 |           "paths": ["/foo/*.pkg"],
170 |           "terminating": false,
171 | 
172 |           // "min_roles_in_agreement" enforces the minimum number of roles that
173 |           // must be in agreement about entrusted targets.  Clients should
174 |           // ignore target files that are not signed off by a
175 |           // "min_roles_in_agreement" of roles in this delegation.
176 |           "min_roles_in_agreement": 1,
177 | 
178 |           // We can specify the names of multiple roles, each of which is
179 |           // associated with its own keys and a threshold number of keys.
180 |           // However, here we specify the name of a single role.
181 |           "roleinfo": [
182 |             {
183 |             // This role must sign them using all 3 of these keys.
184 |               "rolename": "alice",
185 |               "keyids": [
186 |                 "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb",
187 |                 "acac86c0e609ca906f632b0e2dacccb2b77d22b0621f20ebece1a4835b93f6f0",
188 |                 "de7d1b721a1e0632b7cf04edf5032c8ecffa9f9a08492152b926f1a5a7e765d7"
189 |               ],
190 |               "threshold": 3
191 |             }
192 |           ]
193 |         },
194 |         // The second delegation requires that at least two roles sign for
195 |         // targets in order to validate them, otherwise the targets cannot be
196 |         // validated per this delegation.  'release-engineering',
197 |         // 'quality-assurance', and 'continuous-integration' are entrusted to
198 |         // sign for /baz/*.pkg targets, and any two of these three roles must
199 |         // agree on what's signed because "min_roles_in_agreement" = 2.
200 |         // 'release-engineering' is expected to be signed with the single
201 |         // listed key for that role ("threshold" = 1).  'quality-assurance'
202 |         // must be signed with at least two of the three listed keys for that
203 |         // role ("threshold" = 2).  'continuous-integration' must be signed
204 |         // with a single key ("threshold" = 1).
205 |         {
206 |           "name": "second_delegation",
207 |           "paths": ["/baz/*.pkg"],
208 |           "terminating": true,
209 |           "min_roles_in_agreement": 2,
210 |           "roleinfo": [
211 |             {
212 |             // The "release-engineering" role must sign using this key.
213 |               "rolename": "release-engineering",
214 |               "keyids": [
215 |                 "1a2b4110927d4cba257262f614896179ff85ca1f1353a41b5224ac474ca71cb4"
216 |               ],
217 |               "threshold": 1
218 |             },
219 |             {
220 |             // The quality assurance role must sign using at least 2/3 of these keys.
221 |               "rolename": "quality-assurance",
222 |               "keyids": [
223 |                 "93ec2c3dec7cc08922179320ccd8c346234bf7f21705268b93e990d5273a2a3b",
224 |                 "f2d5020d08aea06a0a9192eb6a4f549e17032ebefa1aa9ac167c1e3e727930d6",
225 |                 "fce9cf1cc86b0945d6a042f334026f31ed8e4ee1510218f198e8d3f191d15309"
226 |               ],
227 |               "threshold": 2
228 |             },
229 |             {
230 |             // The continuous integration role must sign with one key.
231 |               "rolename": "continuous-integration",
232 |               "keyids": [
233 |                 "498aeb78523452123dce43434fff346678768676867bae345353453455432544"
234 |               ],
235 |               "threshold": 1
236 |             },
237 |           ],
238 |           ...
239 |         }
240 |     ]
241 |   }
242 | }
243 | 
244 | 245 | ## Resolving multi-role delegations 246 | 247 | As in the previous version of the specification, delegations continue to be 248 | searched in descending order of priority. The only difference between the 249 | previous and current version of the specification is in the way that the 250 | delegations are processed. 251 | 252 | If a desired target matches a target path pattern in the "paths" attribute of a 253 | delegation, then all roles in the delegation's "roleinfo" attribute must 254 | provide exactly the same hashes and length of the desired target. However, 255 | note that these roles may nevertheless provide different "custom" metadata from 256 | each other about the same target. 257 | 258 | While resolving a multi-role delegation, the outcome of a search varies 259 | depending on how the "terminating" attribute is set. If none of the roles 260 | provide metadata about the desired target, then the rest of the delegations 261 | will be searched (given that the "terminating" attribute is False). If a role 262 | does not provide the required metadata, or provides mismatching metadata, the 263 | search is stopped and an error is reported to the client (given that the 264 | "terminating" attribute is True). For instance: In the preceding example the 265 | second multi-role delegation to the "release-engineering", "quality-assurance", 266 | and "continuous-integration" roles is a terminating delegation. If the client 267 | requests the "/baz/baz-1.0.pkg" target and conflicting hashes and lengths are 268 | specified by the "release-engineering", "quality-assurance", and 269 | "continuous-integration" roles, an error occurs and the client is notified that 270 | "/baz/baz-1.0.pkg" is unavailable. 271 | 272 | Note that if the `min_roles_in_agreement` threshold is less than or equal to 273 | half the number of roles listed in the multi-role delegation, you can have 274 | competing target metadata for the same target. A consistent resolution strategy 275 | across implementations is important, so the strategy to be used is this: 276 | - The most-prior (earliest) role in the list of roles, that specifies target 277 | metadata agreed to by enough roles to reach min_roles_in_agreement, wins. 278 | This means that it will often be necessary to check nearly all the roles in the 279 | multi-role delegation. For example, consider the following case: 280 | 281 | Targets delegates to, in order, [A, B, C, and D] in a multi-role delegation with 282 | min_roles_in_agreement threshold of 2. Those roles list the following target 283 | info for target 1.tgz: 284 | - A lists hash1 and length1 285 | - B lists hash2 and length2 286 | - C lists hash2 and length2 287 | - D lists hash1 and length1. 288 | 289 | The target info verified should be hash1 and length1, as they are listed by the 290 | most-prior role whose listed info meets the min_roles_in_agreement threshold. 291 | 292 | Note that this makes it especially important to abort if any role is missing 293 | or cannot be verified, as it is important not to allow a targeted denial of 294 | service to cause different results (hash2 and length2 in this case, if a 295 | verifiable role A is withheld by a middleman). 296 | 297 | 298 | # Security Analysis 299 | 300 | We argue that this TAP does not change existing security guarantees, because it 301 | uses essentially the same preorder depth-first search algorithm to resolve 302 | delegations. The only difference between the previous and new search algorithm 303 | is that, in any multi-role delegation, a threshold of specified roles must provide the 304 | same hashes and length of that target. This does not interfere with how 305 | prioritized and terminating delegations are used to support the OR relation. 306 | 307 | # Backwards Compatibility 308 | 309 | This TAP is incompatible with previous implementations of TUF because the 310 | targets metadata file format has been changed in a backwards-incompatible 311 | manner. 312 | However, note that it should take very little effort to adapt an existing 313 | implementation to resolve or encode delegations using the new file format. 314 | 315 | # Augmented Reference Implementation 316 | 317 | [TODO: Point to a branch containing an implementation of TAP 3.] 318 | 319 | # Copyright 320 | 321 | This document has been placed in the public domain. 322 | -------------------------------------------------------------------------------- /tap4.md: -------------------------------------------------------------------------------- 1 | * TAP: 4 2 | * Title: Multiple repository consensus on entrusted targets 3 | * Version: 1 4 | * Last-Modified: 24-Jun-2020 5 | * Author: Trishank Karthik Kuppusamy, Sebastien Awwad, Evan Cordell, 6 | Vladimir Diaz, Jake Moshenko, Justin Cappos 7 | * Status: Accepted 8 | * Content-Type: text/markdown 9 | * Created: 09-Sep-2016 10 | * TUF-Version: 1.0.0 11 | 12 | # Abstract 13 | This TAP offers guidance for conducting a secure search for particular targets 14 | across multiple repositories. It discusses how multiple repositories with 15 | separate roots of trust can be required to sign off on the same targets, 16 | effectively creating an AND relation and ensuring any files obtained can be 17 | trusted. In other words, this TAP demonstrates how target names can be mapped 18 | to repositories in a manner similar to the way targets with specific names can 19 | be delegated to different roles. Like delegations, these repository entries 20 | can be ordered/prioritized, and can "terminate" a search if an entrusted target 21 | is unavailable. 22 | 23 | # Motivation 24 | 25 | TAP 4 has been motivated by the following use cases. 26 | 27 | ## Use case 1: obtaining different targets from different repositories 28 | 29 | It may be desirable to use the same instance of TUF to download and verify 30 | different targets hosted on different repositories. For example, a user might 31 | want to obtain some Python packages from their maintainers, and others from 32 | PyPI. In this way, one can securely access all Python packages, regardless of 33 | where they are hosted, and without the need for a different client tool 34 | instance (e.g., copy of ```pip```) for each repository. 35 | 36 | ## Use case 2: hiding sensitive metadata and targets 37 | 38 | Extending the previous example, enterprise users may not wish to upload some 39 | metadata and targets to a public repository because doing so may reveal 40 | sensitive or proprietary information. These users may choose to host 41 | the sensitive metadata and targets on a private repository, while still 42 | employing a public repository for other files. However, in order to use both 43 | private and public repositories, TUF clients need to know how to search for 44 | selected targets on the private repository, and all other targets on the public 45 | repository. 46 | 47 | ## Use case 3: improving compromise-resilience given multiple repositories 48 | 49 | To improve compromise-resilience, a user may wish to have multiple 50 | repositories, each with a different root of trust, sign for targets. This 51 | means both repository A and repository B must sign for a target file 52 | before it can be installed. The effect is similar to the AND relation used in 53 | [multi-role delegations](tap3.md), only it is applied to repositories instead 54 | of target delegations. 55 | 56 | Note that if a user is employing multiple repositories with disjointed roots of 57 | trust, it is already possible to do something similar. One could have one 58 | repository download and use a multi-role delegation to the other repository's 59 | target. Thus, if repository A downloaded the targets metadata from repository 60 | B, and used a multi-role delegation for the targets metadata, it would achieve 61 | a similar result. In this instance, if repository B is compromised, users would 62 | not be impacted because repository A's multi-role delegation will prevent the use 63 | of repository B's malicious targets files. Unfortunately, if repository A's 64 | root role or its top-level targets role were to be compromised, nothing could 65 | prevent users from receiving malicious targets files, even if repository B is 66 | not compromised. If, though, adopters required valid signatures on the metadata 67 | from both repositories, even the compromise described above would not impact 68 | users. 69 | 70 | # Rationale 71 | 72 | As our use cases suggest, there are some implementations that may want to allow 73 | clients to fetch target files from multiple repositories. Yet, in doing so, 74 | users risk receiving malicious files if one of these repositories should be 75 | compromised. This TAP presents an implementation strategy to enable a user to 76 | securely and precisely control the amount of trust given to different 77 | repositories. The guidance here can be applied using any type of 78 | data storage/file format 79 | mechanism, as long as it follows the implementation logic presented here. 80 | 81 | # Specification 82 | 83 | This section shows how to retrieve a target file with a specific type of 84 | name, such as 85 | ```django-2.0.1.tgz```, or ```django*```, or ```*.tar.gz```from a 86 | particular repository. Each repository 87 | has its own root of trust (Root role, etc.) so a compromise of one repository 88 | does not impact others. Using a scheme similar to targets delegations within a 89 | repository, targets may be securely assigned to one or more repositories. 90 | 91 | This TAP requires an additional step before a client can request metadata and 92 | target files from remote repositories. Specifically, it requires that a client 93 | consult a mapping of repositories to file patterns, which lists what repositories 94 | should be searched, and in what order, to find particular files. By editing this 95 | list of mappings, or assignment instructions, the client, or adopter, can 96 | precisely control which repositories are to be trusted for particular target 97 | paths. Clients must also keep all of the metadata for each repository in a 98 | separate directory of their choice. 99 | 100 | The next two sections cover the two main components of this new "pre-update" 101 | step. The first explains the mechanism that assigns a target to the specific 102 | repository or repositories from which it should be retrieved. The second 103 | describes the search logic that uses the mapping mechanism to determine what 104 | repositories are visited, and which must sign off on the client's requested 105 | target files. 106 | 107 | ## Mechanism that Assigns Targets to Repositories 108 | 109 | Adopters must implement a mechanism that directs TUF to the specific repository 110 | (or repositories) from which metadata and target files should be downloaded. 111 | Assignments of files to repositories are controlled by sets of instructions 112 | called mappings. 113 | 114 | Each mapping contains the following elements: 115 | 116 | A. An ordered list of one or more repositories. If the updater is instructed to 117 | contact repositories from this mapping, it tries each repository 118 | in the order listed until a threshold of repositories in agreement about the 119 | metadata has been reached. 120 | 121 | B. A list of file paths associated with the ordered list of one or more 122 | repositories. This element supports implementations like the one outlined in 123 | use case 3, in which the user requires valid signatures from multiple 124 | repositories. The file paths may be condensed as [glob 125 | patterns](https://en.wikipedia.org/wiki/Glob_(programming)). For example, the 126 | updater can be instructed to download paths that resemble the glob pattern 127 | `baz*.tgz` from only the third mapping. 128 | 129 | C. A "terminating" flag that instructs the updater whether to continue 130 | searching subsequent matching mappings for the requested targets file when it 131 | has not been found in the current matching mapping. The list of 132 | repositories within a mapping can indicate/use the terminating flag 133 | independent of repositories in other mappings. 134 | 135 | D. A threshold that indicates the minimum number of repositories in (A) that 136 | are required to sign for the same length and hash of any matching target, as 137 | specified in element (B). 138 | 139 | The four elements above are all that is required to guide the updater in its 140 | search for requested files. 141 | 142 | ## Searching for Files on Multiple Repositories 143 | 144 | ![Figure 1 - Mapping](images/figure-1-tap4.svg) 145 | In the figure above (figure 1), a request is made for `foo-1.0.tgz` and an 146 | ordered list of mappings is consulted to determine which repositories should be 147 | contacted. 148 | 149 | To complete a search using this mechanism, a TUF client will follow these steps: 150 | 151 | 1. Check each mapping, in the listed order, and identify the first mapping that 152 | matches the requested file. In figure 1, the client should choose the second 153 | mapping because the glob pattern (`foo*.tgz`) matches the file. 154 | 155 | 2. Once a mapping is identified for the requested file, TUF metadata is 156 | downloaded and verified from the assigned repositories it lists. Verification 157 | occurs if the length and hashes about the target match across a threshold of 158 | repositories (per element D). Custom targets metadata are exempt from this 159 | requirement. In figure 1, repositories D and F can be contacted to download 160 | metadata, and both repositories must provide matching metadata about 161 | `foo-1.0.tgz` to meet the mapping's threshold of 2. 162 | 163 | 3. If the targets metadata is a match across the specified threshold of repositories, 164 | return this metadata. 165 | 166 | 4. If the metadata is not a match, or if fewer than the threshold of 167 | repositories signed metadata about the desired target, then the client should 168 | take one of the following actions: 169 | 170 | 4.1. If the terminating flag (per element C) is set to true, report that 171 | either the repositories do not agree on the target, or that none of them 172 | have signed for the target. In figure 1, the terminating flag for the 173 | first mapping is True, but since the mapping was not a match, the search 174 | continued to the second mapping. 175 | 176 | 4.2. Otherwise, go back to step 1 and process the next mapping that 177 | matches the requested file. In figure 1, if the second mapping 178 | was not a match, or if none of its repositories signed metadata about 179 | foo-1.0.tgz, the third mapping will still match because its glob 180 | pattern is * (all requested files match). 181 | 182 | ## Example using the Reference Implementation's Map File 183 | 184 | To demonstrate the reference implementation's handling of multiple repository 185 | consensus on entrusted targets, we employ a file named `map.json.` This _map 186 | file_ comes into play when a TUF client requests targets and adheres to the 187 | four elements of the mapping mechanism. 188 | 189 | If the map file is to be used to assign targets to repositories, it will either 190 | be constructed by a user employing the TUF command-line tools, or distributed 191 | by an out-of-band bootstrap process. This file is not intended to be 192 | automatically available or refreshed from a repository. In fact, the map file 193 | is kept on the client, and is only modified by a user who is trusted to 194 | configure the updater instance. 195 | 196 | The map file contains a dictionary that holds two keys, "repositories" and 197 | "mapping." The value of the "repositories" key is another dictionary that 198 | lists the URLs for a set of repositories. Each key in this dictionary 199 | is a _repository name_, and its value is a list of URLs. The repository name 200 | also corresponds to the name of the local directory on the TUF client where 201 | metadata files would be cached. Crucially, this is where the 202 | [root metadata file](tap5.md) for a repository is located. 203 | 204 | The repository will also contain a list of URLs that indicates the location 205 | from which files should be retrieved. Each URL points to a root directory 206 | containing metadata and target files. 207 | 208 | The value of the "mapping" key is a priority-ordered list that maps paths 209 | (i.e., target names) to specific repositories, like the mechanism described 210 | earlier in this document. Every entry in this list is 211 | a dictionary containing the following keys: 212 | 213 | * "paths" specifies a list of target paths of patterns. A desired target must 214 | match a pattern in this list for this mapping to be consulted. 215 | * "repositories" specifies a list of one or more repository names. 216 | * "terminating" is a Boolean attribute indicating whether or not 217 | subsequent mappings should be consulted if the target isn't found in this 218 | mapping. 219 | * "threshold" is the minimum number of roles that must sign for any given 220 | target under "paths". 221 | 222 | 223 | The following is an example of a map file: 224 | 225 | ```javascript 226 | { 227 | // For each repository, its key name is the directory where files, including 228 | // the root metadata file, are cached, and its value is a list of URLs where 229 | // files may be downloaded. 230 | "repositories": { 231 | "Django": ["https://djangoproject.com/"], 232 | "PyPI": ["https://pypi.python.org/"] 233 | }, 234 | // For each set of targets, specify a list of repositories where files may be 235 | // downloaded. 236 | "mapping": [ 237 | { 238 | // Much like target delegation, the order of these entries indicates 239 | // the priority of the delegation. The entries listed first will be 240 | // considered first. 241 | 242 | // Map the targets "/django/django-1.*.tgz" to both Django and PyPI. 243 | "paths": ["/django/django-1.*.tgz"], 244 | "repositories": ["Django", "PyPI"], 245 | 246 | // At least one repository must sign for the same length and hashes 247 | // of the "/django/django-1.*.tgz" targets. 248 | "threshold": 1 249 | 250 | // In this case, the "terminating" attribute is set to false. 251 | "terminating": false, 252 | // Therefore, if this mapping has not signed for "/django/django-1.*.tgz" 253 | // targets, the following mapping will be consulted. 254 | 255 | }, 256 | ... 257 | { 258 | // Map all other targets only to PyPI. 259 | "paths": ["*"], 260 | "repositories": ["PyPI"], 261 | "terminating": true 262 | "threshold": 1 263 | } 264 | ] 265 | } 266 | ``` 267 | 268 | # Security Analysis 269 | 270 | Employing this TAP allows users to securely map targets to one or more 271 | repositories. However, it does not change the way TUF verifies metadata for any 272 | individual repository. Each repository will continue to be treated as it was 273 | previously, with TUF performing the necessary verification of repository metadata. 274 | 275 | In order to avoid accidental denial-of-service attacks when multiple 276 | repositories sign the same targets, there must be a coordinated effort to ensure all 277 | are signing the same targets metadata (i.e., length and hashes). 278 | 279 | # Backwards Compatibility 280 | 281 | This specification is backwards-compatible, though older clients will not 282 | support multiple repository consensus on entrusted target files, and so will 283 | ignore this TAP. These clients may continue to use a single repository. New 284 | clients need to add relatively little code to follow the behavior defined 285 | by TAP 4. However, they must be careful to store the metadata 286 | for each repository separately from others (e.g., by using a different 287 | directory for each repository). 288 | 289 | A TUF repository does not need to change in any way to support this TAP. 290 | 291 | # Augmented Reference Implementation 292 | 293 | There's an implementation of TAP 4 under the `multirepo` package in 294 | [rdimitrov/go-tuf-metadata](https://github.com/rdimitrov/go-tuf-metadata). 295 | It implements the multiple repository consensus on entrusted targets via a 296 | map.json file. The package provides a multi-repository client API for creating 297 | a client, searching for a given target and downloading it all by following 298 | the search algorithm described in TAP 4. 299 | 300 | # Copyright 301 | 302 | This document has been placed in the public domain. 303 | -------------------------------------------------------------------------------- /tap5.md: -------------------------------------------------------------------------------- 1 | * TAP: 5 2 | * Title: Setting URLs for roles in the root metadata file 3 | * Version: 1 4 | * Last-Modified: 20-Jul-2020 5 | * Author: Trishank Karthik Kuppusamy, Sebastien Awwad, Evan Cordell, 6 | Vladimir Diaz, Jake Moshenko, Justin Cappos 7 | * Status: Rejected 8 | * Content-Type: text/markdown 9 | * Created: 24-Sep-2016 10 | 11 | # Abstract 12 | 13 | TAP 5 allows each top-level role in the root metadata file to be optionally 14 | associated with a list of URLs. 15 | This allows the implementation of at least two interesting uses cases. 16 | First, it enables a user to associate a remote repository with a different root 17 | of trust, even if the user does not control this repository. 18 | This allows the user to, for example, restrict trust in a community repository 19 | to a single project. 20 | Second, it enables repository administrators to use mirrors in a safe and 21 | limited way. 22 | Specifically, administrators can instruct TUF clients to always download some 23 | metadata files from the original repository, and others from mirrors, so that 24 | clients are always informed of the latest versions of metadata and, thus, 25 | targets. 26 | 27 | # Motivation 28 | 29 | TAP 5 has been motivated by the following use cases. 30 | 31 | ## Use case 1: restricting trust in a community repository to a single project 32 | 33 | Suppose that the Django software project uses the PyPI community repository to 34 | distribute its software packages, because doing so is more cost-effective than 35 | hosting and maintaining its own repository. 36 | Furthermore, suppose that there is group of enterprise users who trust PyPI only 37 | to install Django packages. 38 | These users must depend on PyPI administrators to 39 | [delegate](https://theupdateframework.io/papers/protect-community-repositories-nsdi2016.pdf) 40 | all Django packages to the correct public keys belonging to the project. 41 | Unfortunately, if the PyPI administrator keys have been compromised, then 42 | attackers can replace this delegation, and deceive these unsuspecting users into 43 | installing malware. 44 | 45 | These users can solve the problem, if they are somehow able to _fix_, only for 46 | themselves, the root of trust on PyPI, such that: (1) PyPI is trusted to provide 47 | only metadata about the Django project, and (2) PyPI cannot change the public 48 | keys used to verify this metadata. 49 | 50 | ## Use case 2: trusting a mirror only for snapshot and targets metadata 51 | 52 | Suppose that PyPI wishes to use a mirror to distribute the bandwidth cost of 53 | serving metadata files. 54 | Compared to the root and timestamp metadata files, which are small and constant 55 | in size for all practical purposes, the snapshot and targets metadata files 56 | incur a larger bandwidth cost. 57 | Thus, it makes sense for PyPI to offload serving the snapshot and targets 58 | metadata files to the mirror, but keep serving the root and timestamp metadata 59 | files itself. 60 | In this manner, it can always serve the latest versions of metadata, instead of 61 | depending on the mirror, which may be more easily compromised, to do so. 62 | Unfortunately, there is no way to implement this use case using the 63 | [previous specification](https://github.com/theupdateframework/python-tuf/blob/70fc8dce367cf09563915afa40cffee524f5b12b/docs/tuf-spec.txt#L766-L776). 64 | 65 | PyPI can solve the problem, if it is somehow able to specify that the snapshot 66 | and targets metadata files should be downloaded from the mirror, but that the 67 | root and timestamp metadata files should be downloaded from PyPI itself. 68 | 69 | # Rationale 70 | 71 | We introduce this TAP because, without it, the users who wished to implement 72 | these use cases would be forced to implement undesirable solutions, such as 73 | requiring the Django project to maintain its own repository, or forgoing the use 74 | of mirrors. 75 | It would be desirable for such users to use a more practical solution that 76 | allows them to implement the use cases described above. 77 | 78 | # Specification 79 | 80 | In order to support these use cases, we propose the following simple extension 81 | to the root metadata file format. 82 | 83 | ## The previous root metadata file format 84 | 85 | In the 86 | [previous specification](https://github.com/theupdateframework/python-tuf/blob/70fc8dce367cf09563915afa40cffee524f5b12b/docs/tuf-spec.txt#L766-L776), 87 | there was no list of URLs associated with each top-level role. 88 | 89 | ```Javascript 90 | { 91 | "signed": { 92 | "roles": { 93 | ROLE: { 94 | "keyids": [KEYID], 95 | "threshold": THRESHOLD 96 | }, 97 | }, 98 | ... 99 | }, 100 | ... 101 | } 102 | ``` 103 | 104 | ## The new root metadata file format 105 | 106 | Using the new root metadata file format, each top-level role can use the new 107 | "URLs" attribute to specify a list of URLs from which it can be updated. 108 | There are three cases regarding this attribute. 109 | _If this list is specified, but empty, then this metadata file shall not be 110 | updated at all._ 111 | Otherwise, if this list is specified, and not empty, then the metadata file 112 | shall be downloaded from each URL, using the order specified in this list, until 113 | it is found. 114 | 115 |
116 | {
117 |   "signed": {
118 |     "roles": {
119 |       ROLE: {
120 |         // This is the only adjustment to the file format.
121 |         // Now, a top-level role may be associated with a list of URLs.
122 |         // If this list is specified, but empty, then it shall not be updated.
123 |         // Otherwise, it shall be downloaded from each URL, using the order
124 |         // specified in this list, until it is found.
125 |         "URLs":       [...],
126 |         "keyids":     [KEYID],
127 |         "threshold":  THRESHOLD
128 |       },
129 |     },
130 |     ...
131 | }
132 | 
133 | 134 | ## Example: restricting trust in a community repository to a single project 135 | 136 | Returning to use case 1, the following root metadata file illustrates how our 137 | group of enterprise users may fix, only for themselves, the root of trust on 138 | PyPI, such that: (1) PyPI is trusted to provide only metadata about the Django 139 | project, and (2) PyPI cannot change the public keys used to verify this 140 | metadata: 141 | 142 | ```Javascript 143 | { 144 | "signed": { 145 | "roles": { 146 | // Use a privately controlled root role instead of the one on PyPI. 147 | "root": { 148 | // Fix the root role to keys controlled by the group of enterprise 149 | // users instead of PyPI administrators. 150 | "keyids": [...], 151 | // And update the root metadata file from a privately controlled server. 152 | "URLs": ["http://example.com/metadata/root.json"], 153 | ... 154 | }, 155 | // Use the timestamp role on PyPI. 156 | "timestamp": {...}, 157 | // Use the snapshot role on PyPI. 158 | "snapshot": {...}, 159 | // Instead of using the top-level targets role on PyPI, which delegates to 160 | // other projects besides Django... 161 | "targets": { 162 | // ...use only the delegated targets role belonging to Django on PyPI. 163 | "URLs": ["https://pypi.python.org/metadata/delegations/Django.json"], 164 | // Fix the targets role to correct keys known to belong to Django. 165 | // All of this prevents PyPI from being able to change this delegation. 166 | "keyids": [...], 167 | ... 168 | }, 169 | ... 170 | }, 171 | ... 172 | }, 173 | ... 174 | } 175 | ``` 176 | 177 | In this example, note that root metadata file is updated from a server 178 | controlled by the group of enterprise users, so that PyPI administrators are 179 | unable to change this root of trust. 180 | This means that their TUF clients would not download the root metadata file from 181 | PyPI. 182 | Similarly, their TUF clients would also not download any targets metadata file 183 | from PyPI, except for the delegated targets metadata files belonging to Django. 184 | However, the timestamp and snapshot metadata files would be downloaded from 185 | PyPI. 186 | 187 | ## Example: trusting a mirror only for snapshot and targets metadata 188 | 189 | Returning to use case 2, PyPI can now specify that the snapshot and targets 190 | metadata files should be downloaded from the mirror, but that the root and 191 | timestamp metadata files should be downloaded from PyPI itself: 192 | 193 | ```Javascript 194 | { 195 | "signed": { 196 | "roles": { 197 | // Use the root role controlled by PyPI. 198 | "root": { 199 | // Fix the role to keys controlled by PyPI administrators. 200 | "keyids": [...], 201 | // And update the metadata file from PyPI. 202 | "URLs": ["https://pypi.python.org/metadata/root.json"], 203 | ... 204 | }, 205 | // Use the timestamp role controlled by PyPI. 206 | "timestamp": { 207 | // Fix the role to keys controlled by PyPI administrators. 208 | "keyids": [...], 209 | // And update the metadata file from PyPI. 210 | "URLs": ["https://pypi.python.org/metadata/timestamp.json"], 211 | ... 212 | }, 213 | // Use the snapshot role controlled by PyPI. 214 | "snapshot": { 215 | // Fix the role to keys controlled by PyPI administrators. 216 | "keyids": [...], 217 | // But update the metadata file from the mirror. 218 | "URLs": ["http://example.com/metadata/snapshot.json"], 219 | ... 220 | }, 221 | // Use the targets role controlled by PyPI. 222 | "targets": { 223 | // Fix the role to keys controlled by PyPI administrators. 224 | "keyids": [...], 225 | // But update the metadata file from the mirror. 226 | "URLs": ["http://example.com/metadata/targets.json"], 227 | ... 228 | }, 229 | ... 230 | }, 231 | ... 232 | }, 233 | ... 234 | } 235 | ``` 236 | 237 | ## Changes to the snapshot metadata file 238 | 239 | Since clients may not download the root metadata file from a repository, the 240 | snapshot metadata file need no longer list the root metadata file. 241 | (However, for [backwards compatibility](#backwards-compatibility), it should 242 | continue to list the root metadata file.) 243 | However, it shall continue to list the top-level and all delegated targets 244 | metadata files. 245 | 246 | ## Downloading metadata and target files 247 | 248 | A TUF client would perform the following six steps while searching for a target 249 | on a repository. 250 | 251 | First, the client loads the latest downloaded [root metadata file](tap5.md), and 252 | ensures that: (1) that it has been signed by a threshold of keys, and (2) it has 253 | not expired. 254 | (If it has not been signed by a threshold of keys, then the client should abort, 255 | and report this error. 256 | If it has expired, then the client should try to update the root metadata file.) 257 | Recall that the URL field may either contain the location to update the files, 258 | or may be empty to say that the repository metadata should not be updated. 259 | We will now explicitly explain the procedure for doing this. 260 | The client tries to update the root metadata file. 261 | Let M denote a non-empty list of URLs already known to be associated with this 262 | repository. 263 | For example, M could be the list of URLS associated with the repository in the 264 | [map file](tap4.md). 265 | Let R denote the list of URLs associated with this top-level role (in this case, 266 | the root role) in the root metadata file. 267 | There are four cases: 268 | 269 | 1. If R is empty, then this metadata file shall not be updated. 270 | 2. If R is not empty, then this metadata file shall be downloaded in order from 271 | each URL in R until it is found. If the file could not be found or verified 272 | using all URLs, then report that it is missing. 273 | 3. If R has been omitted, and M is empty, then this metadata file shall not be 274 | updated. 275 | 4. If R has been omitted, and M is not empty, then this metadata file shall be 276 | downloaded in order from each URL in M until it is found. If the file could not 277 | be found or verified using all URLs, then report that it is missing. 278 | 279 | Second, the client uses similar steps to update the timestamp metadata file. 280 | 281 | Third, the client uses similar steps to update the snapshot metadata file. 282 | 283 | Fourth, the client uses similar steps to update the top-level targets metadata 284 | file. 285 | If R is not empty, then the client should be careful in interpreting the entries 286 | of the snapshot metadata file. 287 | Suppose that R is 288 | `["https://pypi.python.org/metadata/targets/Django.json", "http://example.com/metadata/path/to/foo.json"]`. 289 | If the the top-level targets metadata file is available from the first URL, then 290 | the client would look up the version number for "targets/Django.json", instead 291 | of "targets.json" (for the original top-level targets role), in the snapshot 292 | metadata. 293 | After that, the client would try to find the desired target using the 294 | "targets/Django.json" role. 295 | Otherwise, if the top-level targets metadata file could not be found or verified 296 | using the first URL, but it is available from the second URL, then the client 297 | would try to find the target using the "path/to/foo.json" role, being careful to 298 | first look up the version number of the "path/to/foo.json" role in the snapshot 299 | metadata. 300 | 301 | Fifth, the client uses only M to update delegated targets metadata files. 302 | Each file is downloaded in order from each URL in M until it is found. 303 | If the file could not be found or verified using all URLs, then report that it 304 | is missing. 305 | 306 | Sixth, the client uses a step similar to the previous step to download all 307 | target files. 308 | 309 | # Security Analysis 310 | 311 | Adding a list of URLs to every top-level role in the root metadata file does not 312 | introduce new and significant security issues. 313 | This is because attackers cannot change this information without somehow 314 | compromising a threshold of the root keys. 315 | However, if they have somehow achieved this, then there are far more serious 316 | security attacks to worry about, such as arbitrary software attacks, rather than 317 | redirection to an arbitrary server. 318 | Such redirections are already possible without a key compromise: for example, 319 | the attacker could somehow compromise the DNS configuration for a repository. 320 | Fortunately, TUF is designed to handle such attacks. 321 | 322 | Removing the root metadata file from the snapshot metadata does not 323 | significantly change existing security guarantees. 324 | This is because: (1) mix-and-match attacks are executed by specifying an 325 | inconsistent set of targets metadata files, which does not include the root 326 | metadata file, and (2) a client always attempts to update the root metadata 327 | file (unless instructed otherwise). 328 | One difference is that the downloaded root metadata file may not necessarily be 329 | the latest one available. 330 | Previously, unless the snapshot role was compromised, the repository must make 331 | available the root metadata file with exactly the version number published in 332 | the snapshot metadata. 333 | Now, an attacker may withhold the latest available root metadata file, but the 334 | attacker can never execute replay attacks, because version numbers are always 335 | compared. 336 | 337 | Searching for targets from a delegated targets role (such as the Django project 338 | on PyPI) instead of the top-level targets role also does not introduce security 339 | problems, as long as the root metadata file has distributed the correct keys for 340 | the delegated targets role. 341 | In fact, this may even improve compromise-resilience. 342 | If the root metadata file on disk is not updated at all, or is updated using 343 | different root keys than used by the original repository, the keys for the 344 | delegated targets role cannot be incorrectly revoked and replaced with malicious 345 | keys, even if the original repository has been compromised. 346 | 347 | If users fix the keys used to verify a top-level role on a remote repository, 348 | then they must be careful in tracking and specifying the correct keys for these 349 | roles in order to avoid accidental denial-of-service attacks. 350 | If the original repository revokes and replaces these keys, then these keys 351 | should also be updated accordingly in the custom root metadata file. 352 | 353 | # Backwards Compatibility 354 | 355 | This specification is backwards-compatible with older clients that do not 356 | recognize TAP 5, because they need not be aware of the optional list of URLs 357 | associated with each top-level role. 358 | Furthermore, if the snapshot metadata file continues to list the root metadata 359 | file, then backwards-compatibility continues to be maintained. 360 | 361 | # Augmented Reference Implementation 362 | 363 | [TODO: Point to a branch containing implementation of TAP 5.] 364 | 365 | # Copyright 366 | 367 | This document has been placed in the public domain. 368 | -------------------------------------------------------------------------------- /tap6.md: -------------------------------------------------------------------------------- 1 | * TAP: 6 2 | * Title: Include specification version in metadata 3 | * Version: 1 4 | * Last-Modified: 29-Aug-2017 5 | * Author: David Lawrence, Vladimir Diaz, Justin Cappos 6 | * Status: Final 7 | * Content-Type: text/markdown 8 | * Created: 19-Jan-2017 9 | * Post-History: 06-Oct-2016 10 | * TUF-Version: 1.0.0 11 | 12 | # Abstract 13 | 14 | This TAP requires that the specification's version number, against which 15 | the TUF repository should be assessed for validity, be included in 16 | metadata. 17 | 18 | # Motivation 19 | 20 | As the TUF specification evolves there are likely to be breaking changes. For 21 | example, commit 5d2c8fdc7658a9f7648c38b0c79c0aa09d234fe2 in 22 | github.com/theupdateframework/python-tuf removes the "private" field, which would 23 | break key ID calculations for older clients. Specifying the specification 24 | version a repository is operating under allows clients to determine 25 | whether they are compatible, rather than breaking in undefined ways. 26 | 27 | # Rationale 28 | 29 | TUF clients would enjoy greater stability, consistency, and interoperability as 30 | the TUF specification evolves. 31 | 32 | # Specification 33 | 34 | This TAP proposes adding a new field, named "spec_version", that contains 35 | a string value indicating the specification version of metadata. The field 36 | would be added to the "signed" section of metadata. 37 | 38 | ```javascript 39 | { 40 | "_type" : ROLENAME, 41 | "spec_version" : "1.0", // the new field 42 | "version" : VERSION, 43 | "expires" : EXPIRES, 44 | "keys" : { 45 | KEYID : KEY 46 | , ... }, 47 | "roles" : { 48 | ROLE : { 49 | "keyids" : [ KEYID, ... ] , 50 | "threshold" : THRESHOLD } 51 | , ... } 52 | } 53 | ``` 54 | 55 | The use of a string allows for the inclusion of arbitrary additional versioning 56 | markers commonly in use, such as "alpha", "beta", and "RC". There is an 57 | expectation, based on changes that have already been made to the specification, 58 | that a client will not reliably be able to define that it works in all versions 59 | < X with a single implementation variant, which is the sole argument for using 60 | a numerical data type. Instead it is expected that clients will need to map the 61 | specification version to a particular set of behaviour, using a strategy 62 | pattern approach, the alternative being code littered with logic branches that 63 | fork the behaviour based on the specification version. 64 | 65 | # Security Analysis 66 | 67 | The addition of the "spec_version" field to metadata improves security by 68 | increasing a client's ability to determine the compatibility of its 69 | implementation against the structure of the repository it is attempting to 70 | process. This can allow it to fail in a well defined way when it recognizes it 71 | does not support the specification version in use by the repository. 72 | 73 | # Backwards Compatibility 74 | 75 | The addition of the "spec_version" field is compatible with all existing 76 | consumers. However, clients that do not support it and are used to sign and 77 | publish a new metadata are at risk to strip the field from the metadata. This 78 | will happen in at least the Notary and go-tuf implementations due to their use 79 | of concrete types with defined fields to parse retrieved metadata data. 80 | 81 | # Augmented Reference Implementation 82 | 83 | Pull request [#487](https://github.com/theupdateframework/python-tuf/pull/487) adds 84 | "spec_version" to metadata. 85 | 86 | # Copyright 87 | 88 | This document has been placed in the public domain. 89 | -------------------------------------------------------------------------------- /tap9.md: -------------------------------------------------------------------------------- 1 | * TAP: 9 2 | * Title: Mandatory metadata signing schemes 3 | * Version: 1 4 | * Last-Modified: 25-July-2017 5 | * Author: heartsucker 6 | * Status: Final 7 | * Content-Type: text/markdown 8 | * Created: 20-Jan-2017 9 | * TUF-Version: 1.0.0 10 | 11 | # Abstract 12 | 13 | This was started by the discussion about standardizing signatures in [this 14 | GitHub issue](https://github.com/theupdateframework/python-tuf/issues/425#issuecomment-300792546) 15 | in the main TUF repository. Most of the information and arguments that arose 16 | from that discussion have been captured in this document. 17 | 18 | At present, metadata used in TUF is comprised of two sections: `signatures` and 19 | `signed`. The actual metadata is in the `signed` section while the `signatures` 20 | section contains cryptographic signatures of the data in `signed`. These 21 | cryptographic signatures include a `keyid`, `method`, and `signature`. An 22 | example piece of metadata is provided below. 23 | 24 | ```python 25 | { 26 | "signatures": [ 27 | { 28 | "keyid": "588f02cf6907c3f199b201e845f5a458285e9ae956680e0e2fdcc7987306ef7c", 29 | "method": "rsassa-pss", 30 | "sig": "fce1a97b55076065c7dc7c78fb0206d5dd87db817ccc7bcf83c3cdf..." 31 | } 32 | ], 33 | "signed": { 34 | ... 35 | } 36 | } 37 | ``` 38 | 39 | Multiple security researchers have pointed out that the `signatures` section 40 | exists in attacker controlled space and therefore should have the bare minimum 41 | amount of information in it necessary to validate a signature 42 | ([reference 1](https://github.com/docker/notary/blob/b62321473789c704c02ee4ab68348821a5540d36/docs/resources/ncc_docker_notary_audit_2015_07_31.pdf)). 43 | This TAP explains why and how the `method` field will be moved into a role's 44 | definition such that any given key can use exactly one signature scheme to sign 45 | metadata. 46 | 47 | ## Cure53 Audit of Advanced Telematic Systems GmbH 48 | 49 | The following is taken from [Cure53](https://cure53.de)'s review of the ATS 50 | implementation of TUF/Uptane. 51 | 52 | ### ATS-02-003 Client: Signature method does not have to match key type (Info) 53 | 54 | It was found that it is not necessary for the method field of the signature to 55 | match the key type. The keyid field in the signatures' list is used to select 56 | the key which is then employed for verifying the signature. The keytype of the 57 | matching key is then used to determine the algorithm responsible for the 58 | signature verification. This process ignores the method specified for the 59 | signature. While this does not pose an issue at the moment, if more signature 60 | schemes are being implemented in the future, the ability to control which 61 | scheme is used could potentially lead to security problems and risks. 62 | 63 | A Root file example: 64 | 65 | ```python 66 | { 67 | "signatures": [{ 68 | "keyid": "8c7e2de8e96047a9d473e29c0d35daf5ec79b51addf62...", 69 | "method": "rsassa-pss", 70 | "sig": "oAsb1STplQf......j2XsDvevw==" 71 | }], 72 | "signed": { 73 | "keys": { 74 | "20b1b4c6fd067c1b87c67b80890......": { 75 | "keytype": "RSA", 76 | "keyval": { "public": "-----BEGIN PUBLIC......\n" } 77 | }, 78 | ... 79 | }, 80 | ... 81 | } 82 | ``` 83 | 84 | It is recommended to reconsider whether the method field of a signature is 85 | actually needed. This especially holds when there is a mismatch between how 86 | different clients parse the Root data. For example, a client could trust 87 | the unprotected method field over the protected keytype. In case this field is 88 | not necessary, it should be removed. Alternatively, precautions should be taken 89 | to protect the method field. 90 | 91 | # Motivation 92 | 93 | Moving the `method` field into the signed portion of the metadata removes one 94 | more piece of information from the attacker controled space. It additionally 95 | reduces code complexity by not requiring sanity checks and key-to-scheme 96 | matching on the client side. 97 | 98 | # Rationale 99 | 100 | There are several reasons to favor moving information about the signature method 101 | into a cryptographically verified section of the metadata. 102 | 103 | ## Argument 1: Delegators should choose the signature scheme, not delegatees 104 | 105 | The current system allows a given key for a top-level role or any delegated role 106 | to produce a signature using any scheme that key is capable of. Take this 107 | snippet of a Root file: 108 | 109 | ```python 110 | { 111 | "signatures": [ 112 | ... 113 | ], 114 | "signed": { 115 | ... 116 | "keys": { 117 | "0bde74244f238cd6d4e3839d35a5b248d6cde5759b760ebdbee45a386109a41a": { 118 | "keytype": "rsa", 119 | "keyval": { 120 | "public": "-----BEGIN PUBLIC KEY-----" 121 | } 122 | }, 123 | ... 124 | }, 125 | "roles": { 126 | "targets": { 127 | "keyids": [ 128 | "0bde74244f238cd6d4e3839d35a5b248d6cde5759b760ebdbee45a386109a41a" 129 | ], 130 | "threshold": 1 131 | }, 132 | ... 133 | } 134 | } 135 | } 136 | ``` 137 | 138 | In this instance, the key `0bde74...` would be authorized to sign the 139 | `targets.json` with any possible signing scheme that RSA keys are capable of. If 140 | the client knows how to process this scheme, than it will be valid. This could 141 | be RSASSA-PSS over SHA256 or PKCS#1 (among others). 142 | 143 | There could come a time where a certain signing scheme `S1` becomes deprecated 144 | either because it is found to be insufficiently secure or compliance dictates 145 | that a particular signing scheme `S2` should be used instead. The framework does 146 | not place any limitations on how the client handles multiple signing schemes 147 | associated with a given key type. 148 | 149 | ## Argument 2: Cross-type and intra-type signature/scheme mismatches 150 | 151 | When a client receives a signed piece of metadata, it parses each signature 152 | object which includes a `method` field that describes the method the given key 153 | used to create the signature. It is possible that an attacker can modify the key 154 | in one of two ways: 155 | 156 | 1. **cross-type**: the signature method is changed to use the wrong key type 157 | (e.g., `ed25519` to `rsassa-pss-sha256`) 158 | 2. **intra-type**: the signature method is changed to use the wrong scheme for 159 | the same key type (e.g., `rsa-pkcs1` to `rsassa-pss-sha256`) 160 | 161 | In order to prevent the first class of attacks, a client should do a sanity 162 | check to ensure that the provided `method` is one that the key is actually 163 | capable of generating. However, this does not address the second case of 164 | intra-type attacks. If a client understands multiple signing schemes for a given 165 | key, and one is insecure, the attack could downgrade the signature to a less 166 | secure scheme and the client would accept it. 167 | 168 | Regardless, forcing implementors of TUF to write santity checks is a potential 169 | source of bugs. 170 | 171 | ## Argument 3: There should be exactly one trusted signing scheme per key at any time 172 | 173 | It is possible that a solution to the problem addressed in Argument 2 is that 174 | each key would be assigned some `N` approved signing schemes. This might appear 175 | in the metadata like the following: 176 | 177 | ```python 178 | "keys": { 179 | "0bde74244f238cd6d4e3839d35a5b248d6cde5759b760ebdbee45a386109a41a": { 180 | "keytype": "rsa", 181 | "schemes": [ 182 | "rsassa-pss-sha256", 183 | "rsa-pkcs1-1.5" 184 | ], 185 | "keyval": { 186 | "public": "-----BEGIN PUBLIC KEY-----" 187 | } 188 | }, 189 | ... 190 | } 191 | ``` 192 | 193 | When a signature is made, the `signature` object would still need to have a 194 | `method` key to determine which actual signing key was used otherwise the client 195 | would have to loop over all schemes to see if one can successfully verify the 196 | signature (undesirable). If the goal of this proposal is to limit the amount of 197 | data in the attacker controlled space, this solution would merely limit the ways 198 | in which an attacker could influence how the client behaves without fully 199 | removing this vector. 200 | 201 | The above solution should therefore not be considered, especially given 202 | that it would require parsing an additional field as well as code that performs 203 | the matching: both a possible source of bugs. 204 | 205 | A second solution that has been proposed would be to include the scheme 206 | identifier in the function that calculates a key ID so that a key ID would be 207 | `sha256(scheme_id || encoded_key)` where `||` is string concatenation. Assume in 208 | the following example, the two RSA keys are identical. 209 | 210 | ```python 211 | "keys": { 212 | "0bde74244f238cd6d4e3839d35a5b248d6cde5759b760ebdbee45a386109a41a": { 213 | "keytype": "rsa", 214 | "scheme": "rsassa-pss-sha256" 215 | "keyval": { 216 | "public": "-----BEGIN PUBLIC KEY-----" 217 | } 218 | }, 219 | "f3fb3a9fa44e610c91f5e657d0b07ff2b031fb1241496214b8a17c19166cdd5e": { 220 | "keytype": "rsa", 221 | "scheme": "rsa-pkcs-1.5" 222 | "keyval": { 223 | "public": "-----BEGIN PUBLIC KEY-----" 224 | } 225 | }, 226 | ... 227 | } 228 | ``` 229 | 230 | This itself would be insufficient because when checking a threshold, a client 231 | would have have to check that each key ID calculated in the above way points to 232 | exactly one real key. We would have to calculate a second key ID that is 233 | `sha256(encoded_key)` inside each key object. This adds additional complexity 234 | and, like the above iteration over allowed signing schemes, it is a source of 235 | bugs. 236 | 237 | ## Argument 4: There is no practical reason to allow arbitrary switching of signing schemes 238 | 239 | An argument against this proposal is that forcing a signing key to use exactly 240 | one signing scheme would require the Root role or delegator to re-sign 241 | metadata authorizing the change of signing schemes. This sounds like an 242 | inconvenience or loss of a feature, but this restriction does not degrade the 243 | usability of the framework. The owner of a key may still chose a signing scheme 244 | of their liking and use it so long as the delegator approves. If someone wanted 245 | to change the signing scheme attached to their key, they would follow the 246 | already in place procedures used for rotating to a new key. 247 | 248 | # Specification 249 | 250 | The field `method` and all references to it need to be removed from section 4.2 251 | of the current spec as well as all examples of signed metadata. 252 | 253 | Additionally, section 4.2. should be rewritten to: 254 | 255 | ----------------- 256 | All keys have the format: 257 | 258 | ``` 259 | { "keytype" : KEYTYPE, 260 | "scheme": SCHEME, 261 | "keyval" : KEYVAL } 262 | ``` 263 | 264 | where KEYTYPE is a string describing the type of the key and how it's 265 | used to sign documents. The type determines the interpretation of 266 | KEYVAL. SCHEME is the signature scheme that this key uses to generate 267 | signatures. The client MUST only use the single defined scheme when verifying 268 | signatures. In the event client does not recognize the scheme or the scheme 269 | is incompatible with the key type, then the client MUST NOT attempt to 270 | resolve the error and MUST NOT verify any signatures from the key. 271 | 272 | We define two different key types and three signature schemes below. 273 | 274 | Key types: 'rsa' and 'ed25519' 275 | 276 | Signature schemes: 'rsassa-pss-sha256', 'rsa-pkcsv1.5', and 'ed25519' 277 | 278 | However, TUF is not restricted to any particular key type, 279 | signature scheme, or cryptographic library. 280 | 281 | The 'rsa' format is: 282 | 283 | ``` 284 | { "keytype" : "rsa", 285 | "scheme": "rsassa-pss-sha256|rsa-pkcsv1.5", 286 | "keyval" : { "public" : PUBLIC} 287 | } 288 | ``` 289 | 290 | where PUBLIC is in PEM format and a string. All RSA keys 291 | must be at least 2048 bits. 292 | 293 | The 'ed25519' format is: 294 | 295 | ``` 296 | { "keytype" : "ed25519", 297 | "scheme": "ed25519", 298 | "keyval" : { "public" : PUBLIC} 299 | } 300 | ``` 301 | 302 | where PUBLIC is a 32-byte string. 303 | 304 | ## Example 305 | 306 | Here is the format of a current Root file: 307 | 308 | ```python 309 | { 310 | "signatures": [ 311 | { 312 | "keyid": "ed3c845525d34937bf0584989a76fa300c0a6072de714b11b8dca535e10b9088", 313 | "method": "rsassa-pss-sha256", 314 | "sig": "3a0e4666ffbdb5d80001d1539c6a4c27821c3d69065b17ed02a099591b0b4..." 315 | }, 316 | ], 317 | "signed": { 318 | ... 319 | "keys": { 320 | "ed3c845525d34937bf0584989a76fa300c0a6072de714b11b8dca535e10b9088": { 321 | "keytype": "rsa", 322 | "keyval": { 323 | "public": "-----BEGIN PUBLIC KEY----- " 324 | } 325 | } 326 | } 327 | } 328 | ``` 329 | 330 | And it would be changed to: 331 | 332 |
333 | {
334 |   "signatures": [
335 |     {
336 |     "keyid": "ed3c845525d34937bf0584989a76fa300c0a6072de714b11b8dca535e10b9088",
337 |     "sig": "3a0e4666ffbdb5d80001d1539c6a4c27821c3d69065b17ed02a099591b0b4..."
338 |     },
339 |   ],
340 |   "signed": {
341 |     ...
342 |     "keys": {
343 |       "ed3c845525d34937bf0584989a76fa300c0a6072de714b11b8dca535e10b9088": {
344 |         "keytype": "rsa",
345 |         "scheme": "rsassa-pss-sha256",
346 |         "keyval": {
347 |           "public": "-----BEGIN PUBLIC KEY----- "
348 |        }
349 |     }
350 |   }
351 | }
352 | 
353 | 354 | # Security Analysis 355 | 356 | This proposal increases the net security of TUF by removing information from the 357 | attacker controlled space and thus removing one possible way an attacker could 358 | influence the way a client operates. 359 | 360 | The TAP also increases the amount of control each role has over subordinate 361 | roles. The Root role has complete control over the approved signing schemes of 362 | the other top-level roles, and each top-level role has complete control over the 363 | signing schemes of the delegatees. This control can be used to revoke usage of a 364 | signing scheme that has become insecure or no longer complies with some 365 | external regulation. 366 | 367 | # Backwards Compatibility 368 | 369 | This TAP is **not** backwards compatible with the current specification. 370 | However, it should be relatively easy to migrate clients to the new model. 371 | First, they could be modified to parse the `scheme` field in the signed portion 372 | of the metadata and then only use that scheme to verify metadata. If the scheme 373 | in the `signature` object doesn't match, it should reject the metadata as 374 | invalid. Roles and delegatees could then stop including the `method` field, and 375 | the TAP would be fully implemented. 376 | 377 | # Augmented Reference Implementation 378 | 379 | The reference implementation incorporates TAP 9 380 | [here](https://github.com/secure-systems-lab/securesystemslib/pull/48) and 381 | [here](https://github.com/theupdateframework/python-tuf/pull/484). 382 | 383 | # Copyright 384 | 385 | This document has been placed in the public domain. 386 | --------------------------------------------------------------------------------