mirror of
https://github.com/theupdateframework/python-tuf
synced 2026-05-24 10:08:28 +00:00
Merge branch 'develop' into configurable_hash_algo_hashed_bin_prefix
This commit is contained in:
commit
11ecaeba89
4 changed files with 350 additions and 226 deletions
40
LICENSE.txt
40
LICENSE.txt
|
|
@ -1,33 +1,25 @@
|
|||
This file contains the license for TUF: The Update Framework.
|
||||
The MIT License (MIT)
|
||||
|
||||
It also lists license information for components and source
|
||||
code used by TUF: The Update Framework.
|
||||
Copyright (c) 2010 New York University
|
||||
|
||||
If you got this file as a part of a larger bundle,
|
||||
there may be other license terms that you should be aware of.
|
||||
|
||||
===============================================================================
|
||||
TUF: The Update Framework is distributed under this license:
|
||||
|
||||
Copyright (c) 2010, Justin Samuel and Justin Cappos.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and/or hardware specification (the “Work”) to deal in the Work
|
||||
without restriction, including without limitation the rights to use, copy,
|
||||
modify, merge, publish, distribute, sublicense, and/or sell copies of the Work,
|
||||
and to permit persons to whom the Work is furnished to do so, subject to the
|
||||
following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Work.
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER
|
||||
DEALINGS IN THE WORK.
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
===============================================================================
|
||||
Many files are modified from Thandy and are licensed under the
|
||||
following license:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#Security
|
||||
# Security
|
||||
|
||||
Generally, a software update system is secure if it can be sure that it knows about the latest available updates in a timely manner, any files it downloads are the correct files, and no harm results from checking or downloading files. The details of making this happen are complicated by various attacks that can be carried out against software update systems.
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ snapshot metadata, and thus new updates could never be downloaded.
|
|||
|
||||
* **Vulnerability to key compromises**. An attacker who is able to compromise a single key or less than a given threshold of keys can compromise clients. This includes relying on a single online key (such as only being protected by SSL) or a single offline key (such as most software update systems use to sign files).
|
||||
|
||||
##Design Concepts
|
||||
## Design Concepts
|
||||
|
||||
The design and implementation of TUF aims to be secure against all of the above attacks. A few general ideas drive much of the security of TUF.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
The Update Framework Specification
|
||||
|
||||
7 October 2016
|
||||
2 June 2017
|
||||
Version 1.0 (Draft)
|
||||
|
||||
1. Introduction
|
||||
|
|
@ -9,6 +9,10 @@ Version 1.0 (Draft)
|
|||
|
||||
This document describes a framework for securing software update systems.
|
||||
|
||||
The keywords "MUST," "MUST NOT," "REQUIRED," "SHALL," "SHALL NOT," "SHOULD,"
|
||||
"SHOULD NOT," "RECOMMENDED," "MAY," and "OPTIONAL" in this document are to be
|
||||
interpreted as described in RFC 2119.
|
||||
|
||||
1.2. Motivation
|
||||
|
||||
Software is commonly updated through software update systems. These systems
|
||||
|
|
@ -74,7 +78,7 @@ Version 1.0 (Draft)
|
|||
|
||||
The framework will not have the responsibility of deciding on the correct
|
||||
course of action in all error situations, such as those that can occur when
|
||||
certain attacks are being performed. Instead, the framework will provide
|
||||
certain attacks are being performed. Instead, the framework will provide
|
||||
the software update system the relevant information about any errors that
|
||||
require security decisions which are situation-specific. How those errors
|
||||
are handled is up to the software update system.
|
||||
|
|
@ -134,31 +138,31 @@ Version 1.0 (Draft)
|
|||
the client system. That is, an attacker can provide arbitrary files in
|
||||
response to download requests and the files will not be detected as
|
||||
illegitimate.
|
||||
|
||||
|
||||
Endless data attacks. Attackers should not be able to respond to client
|
||||
requests with huge amounts of data (extremely large files) that interfere
|
||||
with the client's system.
|
||||
|
||||
|
||||
Extraneous dependencies attacks. Attackers should not be able to cause
|
||||
clients to download or install software dependencies that are not the
|
||||
intended dependencies.
|
||||
|
||||
|
||||
Fast-forward attacks. An attacker arbitrarily increases the version numbers
|
||||
of project metadata files in the snapshot metadata well beyond the current
|
||||
of project metadata files in the snapshot metadata well beyond the current
|
||||
value, thus tricking a software update system into thinking any subsequent
|
||||
updates are trying to rollback the package to a previous, out-of-date version.
|
||||
In some situations, such as those where there is a maximum possible version
|
||||
number, the perpetrator could use a number so high that the system would
|
||||
never be able to match it with the one in the snapshot metadata, and thus
|
||||
new updates could never be downloaded.
|
||||
|
||||
|
||||
Indefinite freeze attacks. Attackers should not be able to respond to
|
||||
client requests with the same, outdated metadata without the client being
|
||||
aware of the problem.
|
||||
|
||||
|
||||
Malicious mirrors preventing updates. Repository mirrors should be unable
|
||||
to prevent updates from good mirrors.
|
||||
|
||||
|
||||
Mix-and-match attacks. Attackers should not be able to trick clients into
|
||||
using a combination of metadata that never existed together on the
|
||||
repository at the same time.
|
||||
|
|
@ -170,7 +174,7 @@ Version 1.0 (Draft)
|
|||
Slow retrieval attacks. Attackers should not be able to prevent clients
|
||||
from being aware of interference with receiving updates by responding to
|
||||
client requests so slowly that automated updates never complete.
|
||||
|
||||
|
||||
Vulnerability to key compromises. An attacker who is able to compromise a
|
||||
single key or less than a given threshold of keys can compromise clients.
|
||||
This includes relying on a single online key (such as only being protected
|
||||
|
|
@ -207,7 +211,7 @@ Version 1.0 (Draft)
|
|||
the file. As providing additional information about
|
||||
target files may be important to some software update systems using the
|
||||
framework, additional arbitrary information can be provided with any target
|
||||
file. This information will be included in signed metadata that describes
|
||||
file. This information will be included in signed metadata that describes
|
||||
the target files.
|
||||
|
||||
The following are the high-level steps of using the framework from the
|
||||
|
|
@ -277,7 +281,7 @@ Version 1.0 (Draft)
|
|||
(that is, another set of keys and the threshold required for trust) is
|
||||
trusted to sign target file metadata. Partial trust delegation is when the
|
||||
delegated role is only trusted for some of the target files that the
|
||||
delegating role is trusted for.
|
||||
delegating role is trusted for.
|
||||
|
||||
Delegated developer roles can further delegate trust to other delegated
|
||||
roles. This provides for multiple levels of trust delegation where each
|
||||
|
|
@ -415,7 +419,7 @@ Version 1.0 (Draft)
|
|||
provides one signed metadata file. As is the case with the directory
|
||||
structure of top-level metadata, the delegated files are relative to the
|
||||
base URL of metadata available from a given repository mirror.
|
||||
|
||||
|
||||
A delegated role file is located at:
|
||||
|
||||
/DELEGATED_ROLE.json
|
||||
|
|
@ -425,7 +429,7 @@ Version 1.0 (Draft)
|
|||
named ANOTHER_ROLE, that role's signed metadata file is made available at:
|
||||
|
||||
/ANOTHER_ROLE.json
|
||||
|
||||
|
||||
4. Document formats
|
||||
|
||||
All of the formats described below include the ability to add more
|
||||
|
|
@ -443,7 +447,7 @@ Version 1.0 (Draft)
|
|||
4.2. File formats: general principles
|
||||
|
||||
All signed metadata objects have the format:
|
||||
|
||||
|
||||
{ "signed" : ROLE,
|
||||
"signatures" : [
|
||||
{ "keyid" : KEYID,
|
||||
|
|
@ -460,18 +464,18 @@ Version 1.0 (Draft)
|
|||
The current reference implementation of TUF defines two signing methods,
|
||||
although TUF is not restricted to any particular key signing method,
|
||||
key type, or cryptographic library:
|
||||
|
||||
|
||||
"RSASSA-PSS" : RSA Probabilistic signature scheme with appendix.
|
||||
The underlying hash function is SHA256.
|
||||
|
||||
|
||||
"ed25519" : Elliptic curve digital signature algorithm based on Twisted
|
||||
Edwards curves.
|
||||
|
||||
RSASSA-PSS: https://tools.ietf.org/html/rfc3447#page-29
|
||||
|
||||
RSASSA-PSS: https://tools.ietf.org/html/rfc3447#page-29
|
||||
ed25519: https://ed25519.cr.yp.to/
|
||||
|
||||
|
||||
All keys have the format:
|
||||
|
||||
|
||||
{ "keytype" : KEYTYPE,
|
||||
"keyval" : KEYVAL }
|
||||
|
||||
|
|
@ -480,9 +484,9 @@ Version 1.0 (Draft)
|
|||
KEYVAL.
|
||||
|
||||
We define two keytypes at present: 'rsa' and 'ed25519'.
|
||||
|
||||
|
||||
The 'rsa' format is:
|
||||
|
||||
|
||||
{ "keytype" : "rsa",
|
||||
"keyval" : { "public" : PUBLIC}
|
||||
}
|
||||
|
|
@ -491,16 +495,16 @@ Version 1.0 (Draft)
|
|||
must be at least 2048 bits.
|
||||
|
||||
The 'ed25519' format is:
|
||||
|
||||
|
||||
{ "keytype" : "ed25519",
|
||||
"keyval" : { "public" : PUBLIC}
|
||||
}
|
||||
|
||||
where PUBLIC is a 32-byte string.
|
||||
|
||||
|
||||
The KEYID of a key is the hexdigest of the SHA-256 hash of the
|
||||
canonical JSON form of the key.
|
||||
|
||||
|
||||
Metadata date-time data follows the ISO 8601 standard. The expected format
|
||||
of the combined date and time string is "YYYY-MM-DDTHH:MM:SSZ". Time is
|
||||
always in UTC, and the "Z" time zone designator is attached to indicate a
|
||||
|
|
@ -518,6 +522,8 @@ Version 1.0 (Draft)
|
|||
The "signed" portion of root.json is as follows:
|
||||
|
||||
{ "_type" : "Root",
|
||||
"compression_algorithms": [ COMPRESSION_ALGORITHM, ... ],
|
||||
"consistent_snapshot": CONSISTENT_SNAPSHOT,
|
||||
"version" : VERSION,
|
||||
"expires" : EXPIRES,
|
||||
"keys" : {
|
||||
|
|
@ -530,6 +536,15 @@ Version 1.0 (Draft)
|
|||
, ... }
|
||||
}
|
||||
|
||||
COMPRESSION_ALGORITHM specifies one of the compression algorithms supported
|
||||
by the repository. Metadata files available on the repository may
|
||||
optionally be compressed with this algorithm. Compressed versions of
|
||||
metadata are not listed in snapshot.json.
|
||||
|
||||
CONSISTENT_SNAPSHOT is a boolean indicating whether the repository supports
|
||||
consistent snapshots. Section 7 goes into more detail on the consequences
|
||||
of enabling this setting on a repository.
|
||||
|
||||
VERSION is an integer that is greater than 0. Clients MUST NOT replace a
|
||||
metadata file with a version number less than the one currently trusted.
|
||||
|
||||
|
|
@ -556,68 +571,68 @@ Version 1.0 (Draft)
|
|||
{
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "f2d5020d08aea06a0a9192eb6a4f549e17032ebefa1aa9ac167c1e3e727930d6",
|
||||
"method": "ed25519",
|
||||
"keyid": "f2d5020d08aea06a0a9192eb6a4f549e17032ebefa1aa9ac167c1e3e727930d6",
|
||||
"method": "ed25519",
|
||||
"sig": "a312b9c3cb4a1b693e8ebac5ee1ca9cc01f2661c14391917dcb111517f72370809
|
||||
f32c890c6b801e30158ac4efe0d4d87317223077784c7a378834249d048306"
|
||||
}
|
||||
],
|
||||
],
|
||||
"signed": {
|
||||
"_type": "Root",
|
||||
"consistent_snapshot": false,
|
||||
"expires": "2030-01-01T00:00:00Z",
|
||||
"_type": "Root",
|
||||
"consistent_snapshot": false,
|
||||
"expires": "2030-01-01T00:00:00Z",
|
||||
"keys": {
|
||||
"1a2b4110927d4cba257262f614896179ff85ca1f1353a41b5224ac474ca71cb4": {
|
||||
"keytype": "ed25519",
|
||||
"keytype": "ed25519",
|
||||
"keyval": {
|
||||
"public": "72378e5bc588793e58f81c8533da64a2e8f1565c1fcc7f253496394ffc52542c"
|
||||
}
|
||||
},
|
||||
},
|
||||
"93ec2c3dec7cc08922179320ccd8c346234bf7f21705268b93e990d5273a2a3b": {
|
||||
"keytype": "ed25519",
|
||||
"keytype": "ed25519",
|
||||
"keyval": {
|
||||
"public": "68ead6e54a43f8f36f9717b10669d1ef0ebb38cee6b05317669341309f1069cb"
|
||||
}
|
||||
},
|
||||
},
|
||||
"f2d5020d08aea06a0a9192eb6a4f549e17032ebefa1aa9ac167c1e3e727930d6": {
|
||||
"keytype": "ed25519",
|
||||
"keytype": "ed25519",
|
||||
"keyval": {
|
||||
"public": "66dd78c5c2a78abc6fc6b267ff1a8017ba0e8bfc853dd97af351949bba021275"
|
||||
}
|
||||
},
|
||||
},
|
||||
"fce9cf1cc86b0945d6a042f334026f31ed8e4ee1510218f198e8d3f191d15309": {
|
||||
"keytype": "ed25519",
|
||||
"keytype": "ed25519",
|
||||
"keyval": {
|
||||
"public": "01c61f8dc7d77fcef973f4267927541e355e8ceda757e2c402818dad850f856e"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"roles": {
|
||||
"root": {
|
||||
"keyids": [
|
||||
"f2d5020d08aea06a0a9192eb6a4f549e17032ebefa1aa9ac167c1e3e727930d6"
|
||||
],
|
||||
],
|
||||
"threshold": 1
|
||||
},
|
||||
},
|
||||
"snapshot": {
|
||||
"keyids": [
|
||||
"fce9cf1cc86b0945d6a042f334026f31ed8e4ee1510218f198e8d3f191d15309"
|
||||
],
|
||||
],
|
||||
"threshold": 1
|
||||
},
|
||||
},
|
||||
"targets": {
|
||||
"keyids": [
|
||||
"93ec2c3dec7cc08922179320ccd8c346234bf7f21705268b93e990d5273a2a3b"
|
||||
],
|
||||
],
|
||||
"threshold": 1
|
||||
},
|
||||
},
|
||||
"timestamp": {
|
||||
"keyids": [
|
||||
"1a2b4110927d4cba257262f614896179ff85ca1f1353a41b5224ac474ca71cb4"
|
||||
],
|
||||
],
|
||||
"threshold": 1
|
||||
}
|
||||
},
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
|
|
@ -648,7 +663,7 @@ Version 1.0 (Draft)
|
|||
|
||||
METAPATH is the the metadata file's path on the repository relative to the
|
||||
metadata base URL.
|
||||
|
||||
|
||||
The HASHES and LENGTH are the hashes and length of the file, both of which
|
||||
are only specified for the root file. VERSION is listed for the root file
|
||||
and all other roles available on the repository. LENGTH is an integer.
|
||||
|
|
@ -660,31 +675,31 @@ Version 1.0 (Draft)
|
|||
{
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "fce9cf1cc86b0945d6a042f334026f31ed8e4ee1510218f198e8d3f191d15309",
|
||||
"method": "ed25519",
|
||||
"keyid": "fce9cf1cc86b0945d6a042f334026f31ed8e4ee1510218f198e8d3f191d15309",
|
||||
"method": "ed25519",
|
||||
"sig": "f7f03b13e3f4a78a23561419fc0dd741a637e49ee671251be9f8f3fceedfc112e4
|
||||
4ee3aaff2278fad9164ab039118d4dc53f22f94900dae9a147aa4d35dcfc0f"
|
||||
}
|
||||
],
|
||||
],
|
||||
"signed": {
|
||||
"_type": "Snapshot",
|
||||
"expires": "2030-01-01T00:00:00Z",
|
||||
"_type": "Snapshot",
|
||||
"expires": "2030-01-01T00:00:00Z",
|
||||
"meta": {
|
||||
"root.json": {
|
||||
"hashes": {
|
||||
"sha256": "52bbb30f683d166fae5c366e4582cfe8212aacbe1b21ae2026dae58ec55d3701"
|
||||
},
|
||||
},
|
||||
"length": 1831,
|
||||
"version": 1
|
||||
},
|
||||
},
|
||||
"targets.json": {
|
||||
"version": 1
|
||||
},
|
||||
},
|
||||
"project.json": {
|
||||
"version": 1
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
|
||||
|
|
@ -731,12 +746,25 @@ Version 1.0 (Draft)
|
|||
"keyids" : [ KEYID, ... ] ,
|
||||
"threshold" : THRESHOLD,
|
||||
("path_hash_prefixes" : [ HEX_DIGEST, ... ] |
|
||||
"paths" : [ PATHPATTERN, ... ])
|
||||
"paths" : [ PATHPATTERN, ... ]),
|
||||
"terminating": TERMINATING,
|
||||
}, ... ]
|
||||
}
|
||||
|
||||
ROLENAME is the full name of the delegated role. For example,
|
||||
"targets/projects"
|
||||
|
||||
ROLENAME is the name of the delegated role. For example,
|
||||
"projects".
|
||||
|
||||
TERMINATING is a boolean indicating whether subsequent delegations should be
|
||||
considered.
|
||||
|
||||
As explained in the Diplomat paper
|
||||
(https://github.com/theupdateframework/tuf/blob/develop/docs/papers/protect-community-repositories-nsdi2016.pdf),
|
||||
terminating delegations instruct the client not to consider future trust
|
||||
statements that match the delegation's pattern, which stops the delegation
|
||||
processing once this delegation (and its descendants) have been processed.
|
||||
A terminating delegation for a package causes any further statements about
|
||||
a package that are not made by the delegated party or its descendants to
|
||||
be ignored.
|
||||
|
||||
In order to discuss target paths, a role MUST specify only one of the
|
||||
"path_hash_prefixes" or "paths" attributes, each of which we discuss next.
|
||||
|
|
@ -754,31 +782,24 @@ Version 1.0 (Draft)
|
|||
The "paths" list describes paths that the role is trusted to provide.
|
||||
Clients MUST check that a target is in one of the trusted paths of all roles
|
||||
in a delegation chain, not just in a trusted path of the role that describes
|
||||
the target file. The format of a PATHPATTERN may be either a path to a
|
||||
single file, or a path to a directory to indicate all files and/or
|
||||
subdirectories under that directory.
|
||||
the target file. PATHPATTERN can include shell-style wildcards and supports
|
||||
the Unix filename pattern matching convention. Its format may either
|
||||
indicate a path to a single file, or to multiple paths with the use of
|
||||
shell-style wildcards. For example, the path pattern "targets/*.tgz" would
|
||||
match file paths "targets/foo.tgz" and "targets/bar.tgz", but not
|
||||
"targets/foo.txt". Likewise, path pattern "foo-version-?.tgz" matches
|
||||
foo-version-2.tgz" and "foo-version-a.tgz", but not "foo-version-alpha.tgz".
|
||||
|
||||
A path to a directory is used to indicate all possible targets sharing that
|
||||
directory as a prefix; e.g. if the directory is "targets/A", then targets
|
||||
which match that directory include "targets/A/B.json" and
|
||||
"targets/A/B/C.json".
|
||||
|
||||
We are currently investigating a few "priority tag" schemes to resolve
|
||||
conflicts between delegated roles that share responsibility for overlapping
|
||||
target paths. One of the simplest of such schemes is for the client to
|
||||
consider metadata in order of appearance of delegations; we treat the order
|
||||
of delegations such that the first delegation is trusted more than the
|
||||
second one, the second delegation is trusted more than the third one, and so
|
||||
on. The metadata of the first delegation will override that of the second
|
||||
delegation, the metadata of the second delegation will override that of the
|
||||
third delegation, and so on. In order to accommodate this scheme, the
|
||||
"roles" key in the DELEGATIONS object above points to an array, instead of a
|
||||
hash table, of delegated roles.
|
||||
|
||||
Another priority tag scheme would have the clients prefer the delegated role
|
||||
with the latest metadata for a conflicting target path. Similar ideas were
|
||||
explored in the Stork package manager (University of Arizona Tech Report
|
||||
08-04)[https://isis.poly.edu/~jcappos/papers/cappos_stork_dissertation_08.pdf].
|
||||
Prioritized delegations allow clients to resolve conflicts between delegated
|
||||
roles that share responsibility for overlapping target paths. To resolve
|
||||
conflicts, clients must consider metadata in order of appearance of delegations;
|
||||
we treat the order of delegations such that the first delegation is trusted
|
||||
over the second one, the second delegation is trusted more than the third
|
||||
one, and so on. Likewise, the metadata of the first delegation will override that
|
||||
of the second delegation, the metadata of the second delegation will override
|
||||
that of the third one, etc. In order to accommodate prioritized
|
||||
delegations, the "roles" key in the DELEGATIONS object above points to an array
|
||||
of delegated roles, rather than to a hash table.
|
||||
|
||||
The metadata files for delegated target roles has the same format as the
|
||||
top-level targets.json metadata file.
|
||||
|
|
@ -788,51 +809,51 @@ Version 1.0 (Draft)
|
|||
{
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "93ec2c3dec7cc08922179320ccd8c346234bf7f21705268b93e990d5273a2a3b",
|
||||
"method": "ed25519",
|
||||
"keyid": "93ec2c3dec7cc08922179320ccd8c346234bf7f21705268b93e990d5273a2a3b",
|
||||
"method": "ed25519",
|
||||
"sig": "e9fd40008fba263758a3ff1dc59f93e42a4910a282749af915fbbea1401178e5a0
|
||||
12090c228f06db1deb75ad8ddd7e40635ac51d4b04301fce0fd720074e0209"
|
||||
}
|
||||
],
|
||||
],
|
||||
"signed": {
|
||||
"_type": "Targets",
|
||||
"_type": "Targets",
|
||||
"delegations": {
|
||||
"keys": {
|
||||
"ce3e02e72980b09ca6f5efa68197130b381921e5d0675e2e0c8f3c47e0626bba": {
|
||||
"keytype": "ed25519",
|
||||
"keytype": "ed25519",
|
||||
"keyval": {
|
||||
"public": "b6e40fb71a6041212a3d84331336ecaa1f48a0c523f80ccc762a034c727606fa"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
"roles": [
|
||||
{
|
||||
"keyids": [
|
||||
"ce3e02e72980b09ca6f5efa68197130b381921e5d0675e2e0c8f3c47e0626bba"
|
||||
],
|
||||
"name": "targets/project",
|
||||
],
|
||||
"name": "project",
|
||||
"paths": [
|
||||
"/project/file3.txt"
|
||||
],
|
||||
],
|
||||
"threshold": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"expires": "2030-01-01T00:00:00Z",
|
||||
},
|
||||
"expires": "2030-01-01T00:00:00Z",
|
||||
"targets": {
|
||||
"/file1.txt": {
|
||||
"hashes": {
|
||||
"sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da"
|
||||
},
|
||||
},
|
||||
"length": 31
|
||||
},
|
||||
},
|
||||
"/file2.txt": {
|
||||
"hashes": {
|
||||
"sha256": "452ce8308500d83ef44248d8e6062359211992fd837ea9e370e561efb1a4ca99"
|
||||
},
|
||||
},
|
||||
"length": 39
|
||||
}
|
||||
},
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
|
|
@ -864,24 +885,24 @@ Version 1.0 (Draft)
|
|||
{
|
||||
"signatures": [
|
||||
{
|
||||
"keyid": "1a2b4110927d4cba257262f614896179ff85ca1f1353a41b5224ac474ca71cb4",
|
||||
"method": "ed25519",
|
||||
"keyid": "1a2b4110927d4cba257262f614896179ff85ca1f1353a41b5224ac474ca71cb4",
|
||||
"method": "ed25519",
|
||||
"sig": "90d2a06c7a6c2a6a93a9f5771eb2e5ce0c93dd580bebc2080d10894623cfd6eaed
|
||||
f4df84891d5aa37ace3ae3736a698e082e12c300dfe5aee92ea33a8f461f02"
|
||||
}
|
||||
],
|
||||
],
|
||||
"signed": {
|
||||
"_type": "Timestamp",
|
||||
"expires": "2030-01-01T00:00:00Z",
|
||||
"_type": "Timestamp",
|
||||
"expires": "2030-01-01T00:00:00Z",
|
||||
"meta": {
|
||||
"snapshot.json": {
|
||||
"hashes": {
|
||||
"sha256": "c14aeb4ac9f4a8fc0d83d12482b9197452f6adf3eb710e3b1e2b79e8d14cb681"
|
||||
},
|
||||
},
|
||||
"length": 1007,
|
||||
"version": 1
|
||||
}
|
||||
},
|
||||
},
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
|
|
@ -928,61 +949,187 @@ Version 1.0 (Draft)
|
|||
|
||||
5.1. The client application
|
||||
|
||||
1. The client application first instructs TUF to check for updates.
|
||||
0. **Load the previous root metadata file.** We assume that a good, trusted
|
||||
copy of this file was shipped with the package manager / software updater
|
||||
using an out-of-band process.
|
||||
|
||||
2. TUF downloads and verifies timestamp.json.
|
||||
0.1. **Check signatures.** The previous root metadata file MUST have been
|
||||
signed by a threshold of keys specified in the previous root metadata file.
|
||||
|
||||
3. If timestamp.json indicates that snapshot.json has changed, TUF downloads
|
||||
and verifies snapshot.json.
|
||||
0.2. Note that the expiration of the previous root metadata file does not
|
||||
matter, because we will attempt to update it in the next step.
|
||||
|
||||
4. TUF determines which metadata files listed in snapshot.json differ from
|
||||
those described in the last snapshot.json that TUF has seen. If root.json
|
||||
has changed, the update process starts over using the new root.json.
|
||||
1. **Update the root metadata file.** Since it may now be signed using
|
||||
entirely different keys, the client must somehow be able to establish a
|
||||
trusted line of continuity to the latest set of keys (see Section 6.1). To
|
||||
do so, the client MUST download intermediate root metadata files, until the
|
||||
latest available one is reached.
|
||||
|
||||
5. TUF provides the software update system with a list of available files
|
||||
according to targets.json.
|
||||
1.1. Let N denote the version number of the previous root metadata file.
|
||||
|
||||
6. The software update system instructs TUF to download a specific target file.
|
||||
1.2. **Try downloading version N+1 of the root metadata file**, up to some
|
||||
X number of bytes (because the size is unknown). The value for X is set by
|
||||
the authors of the application using TUF. For example, X may be tens of
|
||||
kilobytes. The filename used to download the root metadata file is of the
|
||||
fixed form VERSION.FILENAME.EXT (e.g., 42.root.json). If this file is not
|
||||
available, then go to step 1.8.
|
||||
|
||||
7. TUF downloads and verifies the file and then makes the file available to the
|
||||
software update system.
|
||||
1.3. **Check signatures.** Version N+1 of the root metadata file MUST have
|
||||
been signed by: (1) a threshold of keys specified in the previous root
|
||||
metadata file (version N), and (2) a threshold of keys specified in the
|
||||
current root metadata file (version N+1).
|
||||
|
||||
Note: If at any point in the above procedure there is a problem (i.e., if
|
||||
unexpired, signed, valid metadata cannot be retrieved from the repository),
|
||||
the Root file is downloaded and the process is retried once more (and only
|
||||
once to avoid an infinite loop). Optionally, the software update system
|
||||
using the framework can decide how to proceed rather than automatically
|
||||
downloading a new Root file.
|
||||
1.4. **Check for a rollback attack.** The version number of the previous
|
||||
root metadata file must be less than or equal to the version number of this
|
||||
root metadata file. Effectively, this means checking that the version
|
||||
number signed in the current root metadata file is indeed N+1.
|
||||
|
||||
1.5. **Check for a freeze attack.** The latest known time should be lower
|
||||
than the expiration timestamp in the current root metadata file.
|
||||
|
||||
The client code instructs the framework to check for updates. The framework
|
||||
downloads the timestamp.json file from a mirror and checks that the file is
|
||||
properly signed by the timestamp role, is not expired, and is not older than
|
||||
the last timestamp.json file retrieved. If the timestamp file lists the same
|
||||
snapshot.json file as was previously seen, the client code is informed that no
|
||||
updates are available and the update checking process stops.
|
||||
1.6. Set the previous to the current root metadata file.
|
||||
|
||||
If the snapshot.json file has changed, the framework downloads the file and
|
||||
verifies that it is properly signed by the snapshot role, is not expired, has
|
||||
a newer timestamp than the last snapshot.json file seen, and matches the
|
||||
description (hashes and size) in the timestamp.json file. The framework then
|
||||
checks which metadata files listed in snapshot.json differ from those
|
||||
described in the last snapshot.json file the framework had seen. If the
|
||||
root.json file has changed, the framework updates this (following the same
|
||||
security measures as with the other files) and starts the process over. If
|
||||
any other metadata files have changed, the framework downloads and checks
|
||||
those.
|
||||
1.7. Repeat steps 1.1 to 1.6.
|
||||
|
||||
By comparing the trusted targets from the old trusted metadata with the new
|
||||
metadata, the framework is able to determine which target files have
|
||||
changed. The framework ensures that any targets described in delegated
|
||||
targets files are allowed to be provided by the delegated role.
|
||||
1.8. **If the the timestamp and / or snapshot keys have been rotated, then
|
||||
delete the previous timestamp and snapshot metadata files.** This is done
|
||||
in order to recover from fast-forward attacks after the repository has been
|
||||
compromised and recovered. A _fast-forward attack_ happens when attackers
|
||||
arbitrarily increase the version numbers of: (1) the timestamp metadata,
|
||||
(2) the snapshot metadata, and / or (3) the targets, or a delegated
|
||||
targets, metadata file in the snapshot metadata. Please see [the submitted
|
||||
Mercury
|
||||
draft](https://ssl.engineering.nyu.edu/papers/kuppusamy_usenix_17.pdf) for
|
||||
more details.
|
||||
|
||||
When the client code asks the framework to download a target file, the
|
||||
framework downloads the file from (potentially trying multiple mirrors),
|
||||
checks the downloaded file to ensure that it matches the information
|
||||
described in the targets files, and then makes the file available to the
|
||||
client code.
|
||||
2. **Download the timestamp metadata file**, up to Y number of bytes
|
||||
(because the size is unknown.) The value for Y is set by the authors of the
|
||||
application using TUF. For example, Y may be tens of kilobytes. The
|
||||
filename used to download the timestamp metadata file is of the fixed form
|
||||
FILENAME.EXT (e.g., timestamp.json).
|
||||
|
||||
2.1. **Check signatures.** The timestamp metadata file must have been
|
||||
signed by a threshold of keys specified in the root metadata file.
|
||||
|
||||
2.2. **Check for a rollback attack.** The version number of the previous
|
||||
timestamp metadata file, if any, must be less than or equal to the version
|
||||
number of this timestamp metadata file.
|
||||
|
||||
2.3. **Check for a freeze attack.** The latest known time should be lower
|
||||
than the expiration timestamp in this metadata file.
|
||||
|
||||
3. **Download and check the snapshot metadata file**, up to the number of
|
||||
bytes specified in the timestamp metadata file.
|
||||
If consistent snapshots are not used (see Section 7), then the filename
|
||||
used to download the snapshot metadata file is of the fixed form
|
||||
FILENAME.EXT (e.g., snapshot.json).
|
||||
Otherwise, the filename is of the form VERSION.FILENAME.EXT (e.g.,
|
||||
42.snapshot.json), where VERSION is the version number of the snapshot
|
||||
metadata file listed in the timestamp metadata file. In either case,
|
||||
the client MUST write the file to non-volatile storage as
|
||||
FILENAME.EXT.
|
||||
|
||||
3.1. **Check against timestamp metadata.** The hashes, and version number
|
||||
of this metadata file MUST match the timestamp metadata.
|
||||
|
||||
3.2. **Check signatures.** The snapshot metadata file MUST have been signed
|
||||
by a threshold of keys specified in the previous root metadata file.
|
||||
|
||||
3.3. **Check for a rollback attack.**
|
||||
|
||||
3.3.1. Note that the previous snapshot metadata file may be checked for
|
||||
authenticity, but its expiration does not matter for the following
|
||||
purposes.
|
||||
|
||||
3.3.2. The version number of the previous snapshot metadata file, if any,
|
||||
MUST be less than or equal to the version number of this snapshot metadata
|
||||
file.
|
||||
|
||||
3.3.3. The version number of the targets metadata file, and all delegated
|
||||
targets metadata files (if any), in the previous snapshot metadata file, if
|
||||
any, MUST be less than or equal to its version number in this snapshot
|
||||
metadata file. Furthermore, any targets metadata filename that was listed
|
||||
in the previous snapshot metadata file, if any, MUST continue to be listed
|
||||
in this snapshot metadata file.
|
||||
|
||||
3.4. **Check for a freeze attack.** The latest known time should be lower
|
||||
than the expiration timestamp in this metadata file.
|
||||
|
||||
4. **Download and check the top-level targets metadata file**, up to either
|
||||
the number of bytes specified in the snapshot metadata file, or some
|
||||
Z number of bytes. The value for Z is set by the authors of the application
|
||||
using TUF. For example, Z may be tens of kilobytes.
|
||||
If consistent snapshots are not used (see Section 7), then the filename
|
||||
used to download the targets metadata file is of the fixed form
|
||||
FILENAME.EXT (e.g., targets.json).
|
||||
Otherwise, the filename is of the form VERSION.FILENAME.EXT (e.g.,
|
||||
42.targets.json), where VERSION is the version number of the targets
|
||||
metadata file listed in the snapshot metadata file.
|
||||
In either case, the client MUST write the file to non-volatile storage as
|
||||
FILENAME.EXT.
|
||||
|
||||
4.1. **Check against snapshot metadata.** The hashes (if any), and version
|
||||
number of this metadata file MUST match the snapshot metadata. This is
|
||||
done, in part, to prevent a mix-and-match attack by man-in-the-middle
|
||||
attackers.
|
||||
|
||||
4.2. **Check for an arbitrary software attack.** This metadata file MUST
|
||||
have been signed by a threshold of keys specified in the latest root
|
||||
metadata file.
|
||||
|
||||
4.3. **Check for a rollback attack.** The version number of the previous
|
||||
targets metadata file, if any, MUST be less than or equal to the version
|
||||
number of this targets metadata file.
|
||||
|
||||
4.4. **Check for a freeze attack.** The latest known time should be lower
|
||||
than the expiration timestamp in this metadata file.
|
||||
|
||||
4.5. **Perform a preorder depth-first search for metadata about the desired
|
||||
target, beginning with the top-level targets role.**
|
||||
|
||||
4.5.1. If this role has been visited before, then skip this role (so that
|
||||
cycles in the delegation graph are avoided).
|
||||
Otherwise, if an application-specific maximum number of roles have been
|
||||
visited, then go to step 5 (so that attackers cannot cause the client to
|
||||
waste excessive bandwidth or time).
|
||||
Otherwise, if this role contains metadata about the desired target, then go
|
||||
to step 5.
|
||||
|
||||
4.5.2. Otherwise, recursively search the list of delegations in order of
|
||||
appearance.
|
||||
|
||||
4.5.2.1. If the current delegation is a multi-role delegation, recursively
|
||||
visit each role, and check that each has signed exactly the same non-custom
|
||||
metadata (i.e., length and hashes) about the target (or the lack of any
|
||||
such metadata).
|
||||
|
||||
4.5.2.2. If the current delegation is a terminating delegation, then jump
|
||||
to step 5.
|
||||
|
||||
4.5.2.3. Otherwise, if the current delegation is a non-terminating
|
||||
delegation, continue processing the next delegation, if any. Stop the
|
||||
search, and jump to step 5 as soon as a delegation returns a result.
|
||||
|
||||
5. **Verify the desired target against its targets metadata.**
|
||||
|
||||
5.1. If there is no targets metadata about this target, then report that
|
||||
there is no such target.
|
||||
|
||||
5.2. Otherwise, download the target (up to the number of bytes specified in
|
||||
the targets metadata), and verify that its hashes match the targets
|
||||
metadata. (We download up to this number of bytes, because in some cases,
|
||||
the exact number is unknown. This may happen, for example, if an external
|
||||
program is used to compute the root hash of a tree of targets files, and
|
||||
this program does not provide the total size of all of these files.)
|
||||
If consistent snapshots are not used (see Section 7), then the filename
|
||||
used to download the target file is of the fixed form FILENAME.EXT (e.g.,
|
||||
foobar.tar.gz).
|
||||
Otherwise, the filename is of the form HASH.FILENAME.EXT (e.g.,
|
||||
c14aeb4ac9f4a8fc0d83d12482b9197452f6adf3eb710e3b1e2b79e8d14cb681.foobar.tar.gz),
|
||||
where HASH is one of the hashes of the targets file listed in the targets
|
||||
metadata file found earlier in step 4.
|
||||
In either case, the client MUST write the file to non-volatile storage as
|
||||
FILENAME.EXT.
|
||||
|
||||
6. Usage
|
||||
|
||||
|
|
@ -995,19 +1142,29 @@ Version 1.0 (Draft)
|
|||
stored securely offline (e.g. encrypted and on a separate machine, in
|
||||
special-purpose hardware, etc.). This document does not prescribe how keys
|
||||
should be encrypted and stored, and so it is left to implementers of
|
||||
this document to decide how best to secure them.
|
||||
this document to decide how best to secure them.
|
||||
|
||||
To replace a compromised root key or any other top-level role key, the root
|
||||
role signs a new root.json file that lists the updated trusted keys for the
|
||||
role. When replacing root keys, an application will sign the new root.json
|
||||
file with both the new and old root keys. Any time such a change is
|
||||
required, the root.json file is versioned and accessible by version number,
|
||||
e.g. 3.root.json. Clients update the set of trusted root keys by requesting
|
||||
e.g., 3.root.json. Clients update the set of trusted root keys by requesting
|
||||
the current root.json and all previous root.json versions, until one is
|
||||
found that has been signed by keys the client already trusts. This is to
|
||||
ensure that outdated clients remain able to update, without requiring all
|
||||
previous root keys to be kept to sign new root.json metadata.
|
||||
|
||||
found that has been signed by a threshold of keys that the client already
|
||||
trusts. This is to ensure that outdated clients remain able to update,
|
||||
without requiring all previous root keys to be kept to sign new root.json
|
||||
metadata.
|
||||
|
||||
In the event that the keys being updated are root keys, it is important to
|
||||
note that the new root.json must at least be signed by the keys listed as
|
||||
root keys in the previous version of root.json, up to the threshold listed
|
||||
for root in the previous version of root.json. If this is not the case,
|
||||
clients will (correctly) not validate the new root.json file. For example,
|
||||
if there is a 1.root.json that has threshold 2 and a 2.root.json that has
|
||||
threshold 3, 2.root.json MUST be signed by at least 2 keys defined in
|
||||
1.root.json and at least 3 keys defined in 2.root.json. See step 1 in
|
||||
Section 5.1 for more details.
|
||||
|
||||
To replace a delegated developer key, the role that delegated to that key
|
||||
just replaces that key with another in the signed metadata where the
|
||||
|
|
@ -1037,21 +1194,22 @@ Version 1.0 (Draft)
|
|||
|
||||
Simply put, TUF should write every metadata file as such: if the
|
||||
file had the original name of filename.ext, then it should be written to
|
||||
disk as version_number.filename.ext, where version_number is an integer.
|
||||
|
||||
On the other hand, consistent target files should be written to disk as
|
||||
digest.filename.ext. This means that if the referrer metadata lists N
|
||||
cryptographic hashes of the referred file, then there must be N identical
|
||||
copies of the referred file, where each file will be distinguished only by
|
||||
the value of the digest in its filename. The modified filename need not
|
||||
include the name of the cryptographic hash function used to produce the
|
||||
digest because, on a read, the choice of function follows from the
|
||||
selection of a digest (which includes the name of the cryptographic
|
||||
function) from all digests in the referred file.
|
||||
non-volatile storage as version_number.filename.ext, where version_number
|
||||
is an integer.
|
||||
|
||||
On the other hand, consistent target files should be written to
|
||||
non-volatile storage as digest.filename.ext. This means that if the
|
||||
referrer metadata lists N cryptographic hashes of the referred file, then
|
||||
there must be N identical copies of the referred file, where each file will
|
||||
be distinguished only by the value of the digest in its filename. The
|
||||
modified filename need not include the name of the cryptographic hash
|
||||
function used to produce the digest because, on a read, the choice of
|
||||
function follows from the selection of a digest (which includes the name of
|
||||
the cryptographic function) from all digests in the referred file.
|
||||
|
||||
Additionally, the timestamp metadata (timestamp.json) should also be
|
||||
written to disk whenever it is updated. It is optional for an
|
||||
implementation to write identical copies at digest.timestamp.json for
|
||||
written to non-volatile storage whenever it is updated. It is optional for
|
||||
an implementation to write identical copies at digest.timestamp.json for
|
||||
record-keeping purposes, because a cryptographic hash of the timestamp
|
||||
metadata is usually not known in advance. The same step applies to the root
|
||||
metadata (root.json), although an implementation must write both root.json
|
||||
|
|
@ -1079,32 +1237,7 @@ Version 1.0 (Draft)
|
|||
|
||||
7.2. Reading consistent snapshots
|
||||
|
||||
We now explain how a client should read a self-contained consistent
|
||||
snapshot.
|
||||
|
||||
If the root metadata (root.json) is either missing the Boolean
|
||||
"consistent_snapshot" attribute or the attribute is set to False, then the
|
||||
client should do nothing different from the workflow in Section 5.1.
|
||||
|
||||
Otherwise, the client must perform as follows:
|
||||
1. It must first retrieve the timestamp metadata (timestamp.json) from the
|
||||
repository.
|
||||
2. If a threshold number of signatures of the timestamp or snapshot
|
||||
metadata are not valid, then the client must download the root metadata
|
||||
(root.json) from the repository and return to step 1.
|
||||
3. Otherwise, the client must download every subsequent metadata or
|
||||
target file as follows: if the metadata or target file has the name
|
||||
filename.ext, then the client must actually retrieve the file with the
|
||||
name digest.filename.ext, where digest is the hex digest of a
|
||||
cryptographic hash of the referred file as listed by its referrer file.
|
||||
Even though the modified filename does not include the name of the
|
||||
cryptographic hash function used to produce the chosen digest value, the
|
||||
choice of function follows from the selection of the digest (which
|
||||
includes the name of the cryptographic function) from all digests in the
|
||||
referred file.
|
||||
4. Finally, the client must be careful to rename every metadata or target
|
||||
file retrieved with the name digest.filename.ext to the name
|
||||
filename.ext.
|
||||
See Section 5.1 for more details.
|
||||
|
||||
F. Future directions and open questions
|
||||
|
||||
|
|
@ -1113,4 +1246,3 @@ F.1. Support for bogus clocks.
|
|||
The framework may need to offer an application-enablable "no, my clock is
|
||||
_supposed_ to be wrong" mode, since others have noticed that many users seem
|
||||
to have incorrect clocks.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#updater.py
|
||||
# updater.py
|
||||
**updater.py** is intended as the only TUF module that software update
|
||||
systems need to utilize for a low-level integration. It provides a single
|
||||
class representing an updater that includes methods to download, install, and
|
||||
|
|
@ -152,7 +152,7 @@ for target in updated_target:
|
|||
target_custom_data = target['fileinfo']['custom']
|
||||
```
|
||||
|
||||
###A Simple Integration Example with basic_client.py
|
||||
### A Simple Integration Example with basic_client.py
|
||||
``` Bash
|
||||
# Assume a simple TUF repository has been setup with 'tuf.repository_tool.py'.
|
||||
$ basic_client.py --repo http://localhost:8001
|
||||
|
|
|
|||
Loading…
Reference in a new issue