Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(trdl): server v0 #11

Open
wants to merge 47 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
13eff30
chore(deps): bump securesystemslib from 0.22.0 to 0.24.0 (#383)
dependabot[bot] Sep 14, 2022
6f59db8
chore(trdl): export Repo methods to increment roles versions and expi…
distorhead Jul 21, 2022
040092c
fix: abandon updates if timestamp.json isn't new (#387)
znewman01 Sep 20, 2022
f237d7c
feat: pass logger into repo and client (#385)
asraa Sep 20, 2022
0e33cdf
docs: Add docs for adding and rotating root keys (#389)
mnm678 Sep 21, 2022
7f9beab
chore: update TUF spec version (#392)
znewman01 Sep 21, 2022
8a4aabf
test: update lint CI parameters (#394)
znewman01 Sep 21, 2022
6ea14f5
chore: update TUF spec version to 1.0.31 (#393)
znewman01 Sep 21, 2022
e56ccf6
chore(deps): bump amannn/action-semantic-pull-request from 4.5.0 to 4…
dependabot[bot] Sep 26, 2022
f75cbcc
fix(cmd): fix logging of help message (#395)
asraa Sep 27, 2022
b611a26
docs: fix broken link (#401)
znewman01 Sep 28, 2022
4f55897
test: Do not fail-fast when CI runs. (#403)
vaikas Sep 28, 2022
22f95c0
chore(deps): bump iso8601 from 1.0.2 to 1.1.0 (#404)
dependabot[bot] Sep 29, 2022
2541d68
docs: fix broken link (#405)
abs007 Sep 30, 2022
3890c1e
feat: Add Filesystem based remote store to support airgap. (#397)
vaikas Sep 30, 2022
b4b954d
chore(deps): bump arnested/go-version-action from 1.1.5 to 1.1.6 (#408)
dependabot[bot] Oct 3, 2022
adbdc7d
fix(data): add back SnapshotFileMeta.Custom (#373)
arbll Oct 5, 2022
14853e3
chore: update release notes breaking change regex (#409)
znewman01 Oct 6, 2022
4705874
fix: fix delegation null json value interoperability (#410)
asraa Oct 6, 2022
0f8d7fe
docs: mention breaking changes in PR template (#413)
znewman01 Oct 7, 2022
6f22146
chore(deps): bump actions/setup-python from 4.2.0 to 4.3.0 (#414)
dependabot[bot] Oct 11, 2022
b4c6f5a
chore(deps): bump amannn/action-semantic-pull-request from 4.6.0 to 5…
dependabot[bot] Oct 12, 2022
3f725e2
docs: add security.md (#412)
asraa Oct 13, 2022
39613e3
chore(deps): bump amannn/action-semantic-pull-request from 5.0.0 to 5…
dependabot[bot] Oct 14, 2022
81884a3
chore(deps): bump amannn/action-semantic-pull-request from 5.0.1 to 5…
dependabot[bot] Oct 17, 2022
fff5e69
chore(deps): bump actions/setup-go from 3.3.0 to 3.3.1 (#421)
dependabot[bot] Oct 18, 2022
680a077
chore(deps): bump goreleaser/goreleaser-action from 3.1.0 to 3.2.0 (#…
dependabot[bot] Oct 19, 2022
7d83cf2
chore(deps): bump golangci/golangci-lint-action from 3.2.0 to 3.3.0 (…
dependabot[bot] Oct 21, 2022
64bd805
chore(deps): bump github.com/stretchr/testify from 1.8.0 to 1.8.1 (#424)
dependabot[bot] Oct 24, 2022
047cdb3
fix: fix verification to continue on invalid sigs (#418)
asraa Oct 31, 2022
cfd009d
docs: Remove ethan-lowman-dd from maintainers (#428)
ethan-lowman-dd Nov 3, 2022
2ac63f7
docs: Update MAINTAINERS (#430)
trishankatdatadog Nov 4, 2022
901213d
chore(deps): bump golangci/golangci-lint-action from 3.3.0 to 3.3.1 (…
dependabot[bot] Nov 14, 2022
535756a
chore: Update interop tests for new python-tuf release 2.0.0 (#434)
joshuagl Nov 15, 2022
00e8129
docs: Use Github's vulnerability reporting (#432)
mnm678 Nov 16, 2022
c803c81
chore(deps): bump actions/setup-go from 3.3.1 to 3.4.0 (#435)
dependabot[bot] Dec 2, 2022
9cb61d6
chore: elevate GitHub token permissions for release.yml workflow (#437)
rdimitrov Dec 7, 2022
7e86441
fix(localMeta): Add delegated targets back to localMeta (#384)
BaptisteFoy Jan 9, 2023
3889ddd
chore(deps): bump actions/setup-python from 4.3.0 to 4.4.0 (#443)
dependabot[bot] Jan 11, 2023
f310d5e
chore(deps): bump actions/setup-go from 3.4.0 to 3.5.0 (#441)
dependabot[bot] Jan 11, 2023
a6e32be
chore(deps): bump goreleaser/goreleaser-action from 3.2.0 to 4.1.0 (#…
dependabot[bot] Jan 11, 2023
5f964cf
chore(deps): bump actions/setup-python from 4.4.0 to 4.5.0 (#445)
dependabot[bot] Jan 13, 2023
8f585b5
chore(deps): bump requests from 2.28.1 to 2.28.2 (#446)
dependabot[bot] Jan 13, 2023
66a4473
chore(deps): bump securesystemslib from 0.25.0 to 0.26.0 (#448)
dependabot[bot] Jan 17, 2023
2b21357
chore(deps): bump github.com/dustin/go-humanize from 1.0.0 to 1.0.1 (…
dependabot[bot] Jan 17, 2023
91c85a0
test: add tests for rollback protection on snapshot, targets, delegat…
asraa Jan 24, 2023
5fc1592
Merge tag 'v0.5.2' into trdl_server_0
ilya-lesikov Mar 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
Please fill in the fields below to submit a pull request. The more information that is provided, the better.

Fixes #<Issue>

Release Notes: <!-- What comments/remarks should we include in the release notes for this change? -->

**Types of changes**:
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected). **Please ensure that your PR title** is a [Conventional Commit](https://www.conventionalcommits.org/en/v1.0.0/) breaking change (with a `!`, as in `feat!: change foo`).

**Description of the changes being introduced by the pull request**:

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ jobs:
runs-on: "ubuntu-latest"
steps:
- name:
uses: amannn/action-semantic-pull-request@91682d013dea3ff257520b9b68c9cb93ced4fe9b
uses: amannn/action-semantic-pull-request@01d5fd8a8ebb9aafe902c40c53f0f4744f7381eb
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ on:
tags:
- "v*"
name: CI
permissions:
contents: write
jobs:
tests:
uses: ./.github/workflows/tests.yml
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ jobs:
with:
fetch-depth: 0
- name: Get Go version
uses: arnested/go-version-action@6d27c5921683f55415260f7a285d330ddb146fa2
uses: arnested/go-version-action@b556f8d91b644164318c709d28b9083eaf0c064d
id: go-version
- name: Set up Go
uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568
with:
go-version: ${{ steps.go-version.outputs.minimal }}
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@ff11ca24a9b39f2d36796d1fbd7a4e39c182630a
uses: goreleaser/goreleaser-action@8f67e590f2d095516493f017008adc464e63adb1
with:
distribution: goreleaser
version: "v1.7.0"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/specification-version-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ jobs:
issues: write
uses: theupdateframework/specification/.github/workflows/check-latest-spec-version.yml@master
with:
tuf-version: "v1.0.29" # Should be updated to the according version either manually or extracted automatically as how it's done in python-tuf
tuf-version: "v1.0.31" # Should be updated to the according version either manually or extracted automatically as how it's done in python-tuf
15 changes: 8 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ jobs:
matrix: ${{ steps.versions.outputs.matrix }}
steps:
- uses: actions/checkout@v3
- uses: arnested/go-version-action@6d27c5921683f55415260f7a285d330ddb146fa2
- uses: arnested/go-version-action@b556f8d91b644164318c709d28b9083eaf0c064d
id: versions

run:
strategy:
fail-fast: false # Keep running if one leg fails.
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
go-version: ${{ fromJSON(needs.get-go-versions.outputs.matrix) }}
Expand All @@ -24,12 +25,12 @@ jobs:
uses: actions/checkout@v3

- name: Setup - Go ${{ matrix.go-version }}
uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568
with:
go-version: ${{ matrix.go-version }}

- name: Setup - Python
uses: actions/setup-python@b55428b1882923874294fa556849718a1d7f2ca5
uses: actions/setup-python@d27e3f3d7c64b4bbf8e4abfb9b63b83e846e0435
with:
python-version: "3.10"
cache: "pip"
Expand Down Expand Up @@ -58,12 +59,12 @@ jobs:
runs-on: ${{ matrix.os }}
needs: get-go-versions
steps:
- uses: actions/setup-go@268d8c0ca0432bb2cf416faae41297df9d262d7f
- uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568
with:
go-version: ${{ matrix.go-version }}
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@537aa1903e5d359d0b27dbc19ddd22c5087f3fbc
uses: golangci/golangci-lint-action@0ad9a0988b3973e851ab0a07adf248ec2e100376
with:
version: v1.49.0
args: --timeout 3m
version: v1.49
args: --timeout 5m --verbose
1 change: 1 addition & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ linters:
- gosimple
- unused
- typecheck
- forbidigo
2 changes: 1 addition & 1 deletion .goreleaser/tuf.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ changelog:
use: github
groups:
- title: "Breaking changes"
regexp: "^.*BREAKING CHANGE[(\\w)]*:+.*$"
regexp: "^.*(?:BREAKING CHANGE)|![(\\w)]*:+.*$"
order: 0
- title: Features
regexp: "^.*feat[(\\w)]*:+.*$"
Expand Down
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,39 @@ $ tree .
└── staged
```

#### Adding a new root key

Copy `staged/root.json` to the root box and generate a new root key on the root box:

```bash
$ tuf gen-key root
$ tuf sign root.json
```

Copy `staged/root.json` from the root box and commit:

```bash
$ tuf commit
```

#### Rotating root key(s)

Copy `staged/root.json` to the root box to do the rotation, where `abcd` is the keyid of the key that is being replaced:

```bash
$ tuf gen-key root
$ tuf revoke-key root abcd
$ tuf sign root.json
```

Note that `revoke-key` removes the old key from `root.json`, but the key remains in the `keys/` directory on the root box as it is needed to sign the next `root.json`. After this signing is done, the old key may be removed from `keys/`. Any number of keys may be added or revoked during this step, but ensure that at least a threshold of valid keys remain.

Copy `staged/root.json` from the root box to commit:

```bash
$ tuf commit
```

## Client

For the client package, see https://godoc.org/github.com/theupdateframework/go-tuf/client.
Expand Down
105 changes: 97 additions & 8 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import (
"bytes"
"encoding/hex"
"encoding/json"
"fmt"
"io"

"github.com/theupdateframework/go-tuf/data"
"github.com/theupdateframework/go-tuf/internal/roles"
"github.com/theupdateframework/go-tuf/util"
"github.com/theupdateframework/go-tuf/verify"
)
Expand Down Expand Up @@ -143,7 +145,13 @@ func (c *Client) Update() (data.TargetFiles, error) {
}
// 5.4.(2,3 and 4) - Verify timestamp against various attacks
// Returns the extracted snapshot metadata
snapshotMeta, err := c.decodeTimestamp(timestampJSON)
snapshotMeta, sameTimestampVersion, err := c.decodeTimestamp(timestampJSON)
if sameTimestampVersion {
// The new timestamp.json file had the same version; we don't need to
// update, so bail early.
return c.targets, nil
}

if err != nil {
return nil, err
}
Expand Down Expand Up @@ -393,8 +401,8 @@ func (c *Client) getLocalMeta() error {
}
}

snapshot := &data.Snapshot{}
if snapshotJSON, ok := meta["snapshot.json"]; ok {
snapshot := &data.Snapshot{}
if err := c.db.UnmarshalTrusted(snapshotJSON, snapshot, "snapshot"); err != nil {
loadFailed = true
retErr = err
Expand All @@ -417,13 +425,83 @@ func (c *Client) getLocalMeta() error {
c.loadTargets(targets.Targets)
}
}

if loadFailed {
// If any of the metadata failed to be verified, return the reason for that failure
// and fail fast before delegated targets
return retErr
}

// verifiedDelegatedTargets is a set of verified delegated targets
verifiedDelegatedTargets := make(map[string]bool)
for fileName := range meta {
if !verifiedDelegatedTargets[fileName] && roles.IsDelegatedTargetsManifest(fileName) {
if delegationPath, err := c.getDelegationPathFromRaw(snapshot, meta[fileName]); err != nil {
loadFailed = true
retErr = err
} else {
// Every delegated targets in the path has been verified
// as a side effect of getDelegationPathFromRaw
for _, key := range delegationPath {
fileName := fmt.Sprintf("%s.json", key)
verifiedDelegatedTargets[fileName] = true
}
}
}
}

for fileName := range verifiedDelegatedTargets {
c.localMeta[fileName] = meta[fileName]
}

if loadFailed {
// If any of the metadata failed to be verified, return the reason for that failure
return retErr
}
return nil
}

// getDelegationPathFromRaw verifies a delegated targets against
// a given snapshot and returns an error if it's invalid
//
// Delegation must have targets to get a path, else an empty list
// will be returned: this is because the delegation iterator is leveraged.
//
// Concrete example:
// targets
// └── a.json
//   └── b.json
//      └── c.json
//        └── target_file.txt
//
// If you try to use that function on "a.json" or "b.json", it'll return an empty list
// with no error, as neither of them declare a target file
// On the other hand, if you use that function on "c.json", it'll return & verify
// [c.json, b.json, a.json]. Running that function on every delegated targets
// guarantees that if a delegated targets is in the path of a target file, then it will
// appear at least once in the result
func (c *Client) getDelegationPathFromRaw(snapshot *data.Snapshot, delegatedTargetsJSON json.RawMessage) ([]string, error) {
// unmarshal the delegated targets first without verifying as
// we need at least one targets file name to leverage the
// getTargetFileMetaDelegationPath method
s := &data.Signed{}
if err := json.Unmarshal(delegatedTargetsJSON, s); err != nil {
return nil, err
}
targets := &data.Targets{}
if err := json.Unmarshal(s.Signed, targets); err != nil {
return nil, err
}
for targetPath := range targets.Targets {
_, resp, err := c.getTargetFileMetaDelegationPath(targetPath, snapshot)
// We only need to test one targets file:
// - If it is valid, it means the delegated targets has been validated
// - If it is not, the delegated targets isn't valid
return resp, err
}
return nil, nil
}

// loadAndVerifyLocalRootMeta decodes and verifies root metadata from
// local storage and loads the top-level keys. This method first clears
// the DB for top-level keys and then loads the new keys.
Expand Down Expand Up @@ -740,22 +818,31 @@ func (c *Client) decodeTargets(b json.RawMessage) (data.TargetFiles, error) {
}

// decodeTimestamp decodes and verifies timestamp metadata, and returns the
// new snapshot file meta.
func (c *Client) decodeTimestamp(b json.RawMessage) (data.TimestampFileMeta, error) {
// new snapshot file meta and signals whether the update should be aborted early
// (the new timestamp has the same version as the old one, so there's no need to
// complete the update).
func (c *Client) decodeTimestamp(b json.RawMessage) (data.TimestampFileMeta, bool, error) {
timestamp := &data.Timestamp{}

if err := c.db.Unmarshal(b, timestamp, "timestamp", c.timestampVer); err != nil {
return data.TimestampFileMeta{}, ErrDecodeFailed{"timestamp.json", err}
return data.TimestampFileMeta{}, false, ErrDecodeFailed{"timestamp.json", err}
}
// 5.4.3.1 - Check for timestamp rollback attack
// We already checked for timestamp.Version < c.timestampVer in the Unmarshal call above.
// Here, we're checking for version equality, which indicates that we can abandon this update.
if timestamp.Version == c.timestampVer {
return data.TimestampFileMeta{}, true, nil
}
// 5.4.3.2 - Check for snapshot rollback attack
// Verify that the current snapshot meta version is less than or equal to the new one
if timestamp.Meta["snapshot.json"].Version < c.snapshotVer {
return data.TimestampFileMeta{}, verify.ErrLowVersion{Actual: timestamp.Meta["snapshot.json"].Version, Current: c.snapshotVer}
return data.TimestampFileMeta{}, false, verify.ErrLowVersion{Actual: timestamp.Meta["snapshot.json"].Version, Current: c.snapshotVer}
}
// At this point we can trust the new timestamp and the snaphost version it refers to
// At this point we can trust the new timestamp and the snapshot version it refers to
// so we can update the client's trusted versions and proceed with persisting the new timestamp
c.timestampVer = timestamp.Version
c.snapshotVer = timestamp.Meta["snapshot.json"].Version
return timestamp.Meta["snapshot.json"], nil
return timestamp.Meta["snapshot.json"], false, nil
}

// hasMetaFromSnapshot checks whether local metadata has the given meta
Expand Down Expand Up @@ -792,6 +879,8 @@ type Destination interface {
// - The target does not exist in any targets
// - Metadata cannot be generated for the downloaded data
// - Generated metadata does not match local metadata for the given file
// - Size of the download does not match if the reported size is known and
// incorrect
func (c *Client) Download(name string, dest Destination) (err error) {
// delete dest if there is an error
defer func() {
Expand Down
Loading